<?php

namespace App\Console\Commands;

use App\Models\Booking;
use App\Models\Job;
use App\Models\Customer;
use App\Models\Vehicle;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Schema;

class SyncJobsFromVevsBookings extends Command
{
    protected $signature = 'jobs:sync-from-vevs-bookings 
                            {--all : Process all VEVS bookings (default: only those without jobs)}';

    protected $description = 'Create or update Job records from VEVS-origin Bookings, including money buckets.';

    public function handle(): int
    {
        // Guard: make sure required tables/columns exist
        if (! Schema::hasTable((new Booking)->getTable())) {
            $this->error('Bookings table does not exist.');
            return self::FAILURE;
        }

        if (! Schema::hasTable((new Job)->getTable())) {
            $this->error('Jobs table does not exist.');
            return self::FAILURE;
        }

        $bookingTable = (new Booking)->getTable();

        if (! Schema::hasColumn($bookingTable, 'vevs_car_id')) {
            $this->error("Booking table [{$bookingTable}] does not have a vevs_car_id column.");
            return self::FAILURE;
        }

        $onlyMissingJobs = ! $this->option('all');

        $this->info('Syncing Jobs from VEVS Bookings...');
        $this->line($onlyMissingJobs
            ? 'Mode: only bookings that do not yet have a Job.'
            : 'Mode: ALL VEVS bookings (updating any existing Jobs).'
        );

        $query = Booking::query()
            ->whereNotNull('vevs_car_id');

        if ($onlyMissingJobs) {
            $query->whereDoesntHave('jobs', function ($q) {
                // if you don’t have a jobs() relation on Booking yet,
                // this whereDoesntHave will be ignored – see below
            });
        }

        // If Booking doesn’t have a jobs() relation yet, we’ll just fall back
        // to a manual existence check per row (we handle that below).

        $count = 0;

        $query->chunkById(100, function ($bookings) use (&$count, $onlyMissingJobs) {
            foreach ($bookings as $booking) {
                /** @var Booking $booking */

                // If there is no jobs() relation, fall back to manual check
                $hasJobAlready = Job::where('booking_id', $booking->id)->exists();

                if ($onlyMissingJobs && $hasJobAlready) {
                    continue;
                }

                $job = Job::firstOrNew([
                    'booking_id' => $booking->id,
                ]);

                $this->mapBookingToJob($booking, $job);

                $job->save();

                $count++;
                $this->line("Synced Job for Booking #{$booking->id} (Job ID: {$job->id})");
            }
        });

        $this->info("Done. Synced {$count} job(s).");

        return self::SUCCESS;
    }

    /**
     * Map Booking fields + VEVS meta into the Job model.
     */
    protected function mapBookingToJob(Booking $booking, Job $job): void
    {
        // Basic linkage
        $job->booking_id = $booking->id;

        // Reference / external reference
        if (Schema::hasColumn($booking->getTable(), 'reference')) {
            $job->external_reference = $booking->reference ?? $job->external_reference;
            $job->reference          = $job->reference ?? $booking->reference;
        }

        // If Booking has brand_id and Job has brand_id, copy it
        if (Schema::hasColumn($booking->getTable(), 'brand_id') &&
            Schema::hasColumn($job->getTable(), 'brand_id')) {
            $job->brand_id = $booking->brand_id;
        }

        // Customer info (from relation if present, otherwise from meta)
        $customer = null;
        if (method_exists($booking, 'customer')) {
            /** @var Customer|null $customer */
            $customer = $booking->customer;
        }

        $job->customer_name  = $customer?->full_name
            ?? ($booking->meta['customer']['name'] ?? null)
            ?? $job->customer_name;

        $job->customer_email = $customer?->email
            ?? ($booking->meta['customer']['email'] ?? null)
            ?? $job->customer_email;

        $job->customer_phone = $booking->meta['customer']['phone'] ?? $job->customer_phone;

        // Dates
        if (Schema::hasColumn($booking->getTable(), 'start_at')) {
            $job->start_at = $booking->start_at;
        }
        if (Schema::hasColumn($booking->getTable(), 'end_at')) {
            $job->end_at = $booking->end_at;
        }

        // Primary charge + hold (Booking stores cents already)
        if (Schema::hasColumn($booking->getTable(), 'total_amount')) {
            $job->charge_amount_cents = (int) ($booking->total_amount ?? 0);
        }

        if (Schema::hasColumn($booking->getTable(), 'hold_amount')) {
            $job->hold_amount_cents = (int) ($booking->hold_amount ?? 0);
        }

        // Currency
        if (Schema::hasColumn($booking->getTable(), 'currency') &&
            Schema::hasColumn($job->getTable(), 'currency_code')) {
            $job->currency_code = $booking->currency ?? $job->currency_code ?? 'NZD';
        }

        // Link VEVS car id + optionally resolve Vehicle
        if (Schema::hasColumn($booking->getTable(), 'vevs_car_id') &&
            Schema::hasColumn($job->getTable(), 'vevs_car_id')) {
            $job->vevs_car_id = $booking->vevs_car_id;
        }

        if (class_exists(Vehicle::class) &&
            Schema::hasColumn((new Vehicle)->getTable(), 'vevs_car_id') &&
            Schema::hasColumn($job->getTable(), 'vehicle_id') &&
            $booking->vevs_car_id
        ) {
            $vehicle = Vehicle::where('vevs_car_id', $booking->vevs_car_id)->first();
            if ($vehicle) {
                $job->vehicle_id = $vehicle->id;
            }
        }

        // Status: you can adjust this mapping as needed
        $job->status = $job->status ?? $this->mapBookingStatusToJobStatus($booking->status ?? null);

        // Money buckets from VEVS meta (if available)
        $vevs = [];
        if (is_array($booking->meta ?? null) && isset($booking->meta['vevs_row']) && is_array($booking->meta['vevs_row'])) {
            $vevs = $booking->meta['vevs_row'];
        }

        if ($vevs && method_exists($job, 'fillMoneyFromVevs')) {
            $job->fillMoneyFromVevs($vevs);
        }
    }

    /**
     * Simple status mapping Booking.status → Job.status
     */
    protected function mapBookingStatusToJobStatus(?string $status): string
    {
        if (! $status) {
            return 'pending';
        }

        $status = strtolower(trim($status));

        return match ($status) {
            'paid', 'confirmed', 'completed', 'complete', 'captured', 'succeeded' => 'confirmed',
            'cancelled', 'canceled', 'cancel'                                     => 'cancelled',
            default                                                               => 'pending',
        };
    }
}
