<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\Flow;
use App\Models\Job;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Schema;

class JobImportService
{
    /**
     * Import or update a Job from a raw VEVS booking payload (the "data" block).
     */
    public function importFromVevsPayload(array $payload, ?string $brandKey = null): Job
    {
        // Work out a booking reference – prefer ref_id, with fallbacks.
        $bookingRef = $payload['ref_id']
            ?? $payload['booking_id']
            ?? $payload['uuid']
            ?? $payload['id']
            ?? null;

        if (! $bookingRef) {
            $bookingRef = 'vevs-' . uniqid();
        }

        $jobsTable = (new Job())->getTable();

        // If the jobs table has a booking_reference column, use it to find-or-create.
        if (Schema::hasColumn($jobsTable, 'booking_reference')) {
            $job = Job::firstOrNew([
                'booking_reference' => $bookingRef,
            ]);
        } else {
            // Fallback: no booking_reference column, just create a fresh Job instance.
            $job = new Job();
        }

        // Always set booking_reference if the column exists.
        $this->setIfColumnExists($job, 'booking_reference', $bookingRef);
        $this->setIfColumnExists($job, 'external_reference', $bookingRef);


        // Brand – only if you actually have a brand_key / brand_id column.
        if ($brandKey) {
            if (Schema::hasColumn($jobsTable, 'brand_key')) {
                $job->brand_key = $brandKey;
            }
            // You can later add brand_id lookup here if you want.
        }

        // Dates/times from VEVS (`from` / `to` are "YYYY-MM-DD HH:MM:SS" strings).
        $startAt = $this->parseVevsDateTime(Arr::get($payload, 'from'));
        $endAt   = $this->parseVevsDateTime(Arr::get($payload, 'to'));

        if ($startAt) {
            $this->setIfColumnExists($job, 'start_at', $startAt);
            $this->setIfColumnExists($job, 'start_date', $startAt->toDateString());
            $this->setIfColumnExists($job, 'start_time', $startAt->format('H:i:s'));
        }

        if ($endAt) {
            $this->setIfColumnExists($job, 'end_at', $endAt);
            $this->setIfColumnExists($job, 'end_date', $endAt->toDateString());
            $this->setIfColumnExists($job, 'end_time', $endAt->format('H:i:s'));
        }

        // Vehicle and locations (if present on your jobs table).
        $this->setIfColumnExists($job, 'vehicle_id', Arr::get($payload, 'car_id'));
        $this->setIfColumnExists($job, 'pickup_location_id', Arr::get($payload, 'pickup_id'));
        $this->setIfColumnExists($job, 'return_location_id', Arr::get($payload, 'return_id'));

        // Totals / money
        $totalPrice = $this->toCents(Arr::get($payload, 'total_price'));
        $currency   = Arr::get($payload, 'currency.value', 'NZD');

        if ($totalPrice !== null) {
            $this->setIfColumnExists($job, 'charge_amount_cents', $totalPrice);
        }

        $this->setIfColumnExists($job, 'currency', $currency);

        // Deposits
        $requiredDeposit = Arr::get($payload, 'required_deposit'); // e.g. "501.25"
        $securityDeposit = Arr::get($payload, 'security_deposit'); // e.g. "500.00"

        $this->setIfColumnExists($job, 'required_deposit', $requiredDeposit);
        $this->setIfColumnExists($job, 'security_deposit', $securityDeposit);

        // Basic customer info
        $customerName  = Arr::get($payload, 'c_name')
            ?: trim((Arr::get($payload, 'c_fname', '') . ' ' . Arr::get($payload, 'c_lname', '')))
            ?: Arr::get($payload, 'c_driver_name');

        $customerEmail = Arr::get($payload, 'c_email');
        $customerPhone = Arr::get($payload, 'c_phone');

        $this->setIfColumnExists($job, 'customer_name', $customerName);
        $this->setIfColumnExists($job, 'customer_email', $customerEmail);
        $this->setIfColumnExists($job, 'customer_phone', $customerPhone);

        // External status from VEVS booking
        if (Schema::hasColumn($jobsTable, 'external_status')) {
            $job->external_status = Arr::get($payload, 'status'); // e.g. "confirmed"
        }

        // If you keep a JSON snapshot of the VEVS payload, save just the booking block here.
        if (Schema::hasColumn($jobsTable, 'vevs_snapshot')) {
            $job->vevs_snapshot = json_encode($payload);
        }

        // Ensure a default flow_id if the column exists and is required.
        if (Schema::hasColumn($jobsTable, 'flow_id') && empty($job->flow_id)) {
            $defaultFlow = Flow::query()->first();

            if ($defaultFlow) {
                $job->flow_id = $defaultFlow->id;
            }
        }

        $job->save();

        return $job;
    }

    /**
     * Helper: only set an attribute if the column exists in the table.
     */
    protected function setIfColumnExists(Job $job, string $column, mixed $value): void
    {
        if ($value === null) {
            return;
        }

        $table = $job->getTable();

        if (! Schema::hasColumn($table, $column)) {
            return;
        }

        $job->{$column} = $value;
    }

    /**
     * Parse a VEVS datetime string into a Carbon instance in app timezone.
     */
    protected function parseVevsDateTime(?string $value): ?Carbon
    {
        if (! $value) {
            return null;
        }

        try {
            return Carbon::createFromFormat('Y-m-d H:i:s', $value, config('app.timezone'))
                ->timezone(config('app.timezone'));
        } catch (\Throwable) {
            return null;
        }
    }

    /**
     * Convert a "123.45" style string into integer cents.
     */
    protected function toCents(mixed $value): ?int
    {
        if ($value === null || $value === '') {
            return null;
        }

        $float = (float) $value;

        return (int) round($float * 100);
    }
}
