<?php

namespace App\Filament\Pages;

use App\Models\Job;
use App\Models\OpsTask;
use App\Models\Vehicle;
use Carbon\Carbon;
use Filament\Pages\Page;
use Illuminate\Support\Collection;

class OpsToday extends Page
{
    protected static ?string $navigationIcon  = 'heroicon-o-clipboard-document-check';
    protected static ?string $navigationLabel = "Today's Ops";
    protected static ?string $navigationGroup = 'Operations';
    protected static ?int    $navigationSort  = 0;


    protected static string $view = 'filament.pages.ops-today';

    /** @var \Illuminate\Support\Collection<int,\App\Models\Job> */
    public Collection $pickupsToday;

    /** @var \Illuminate\Support\Collection<int,\App\Models\Job> */
    public Collection $returnsToday;

    /** @var \Illuminate\Support\Collection<int,\App\Models\OpsTask> */
    public Collection $openTasks;

    /** @var \Illuminate\Support\Collection<int,\App\Models\OpsTask> */
    public Collection $overdueTasks;

    /** @var \Illuminate\Support\Collection<int,\App\Models\OpsTask> */
    public Collection $completedTodayTasks;

    /** @var \Illuminate\Support\Collection<int,\App\Models\Vehicle> */
    public Collection $vehicles;

    // Quick-add fields
    public string $newTaskTitle      = '';
    public ?int  $newTaskVehicleId   = null;
    public ?int  $newTaskForUserId   = null;
    public string $newTaskType       = 'other';
    public int    $newTaskPriority   = 2;

    public function mount(): void
    {
        $this->refreshData();
    }

    protected function refreshData(): void
    {
        $today = Carbon::today();

        /*
         * PICKUPS TODAY
         * We deliberately use Job::query() (no status filter) so ALL hires show,
         * and we eager-load vehicle for display.
         * We also strip any malformed UTF-8 so Livewire/json_encode never explode.
         */
        $this->pickupsToday = $this->applyBrandScope(
            Job::query()
                ->whereNotNull('start_at')
                ->whereDate('start_at', $today)
                ->with('vehicle')
                ->orderBy('start_at')
        )
            ->get()
            ->map(function (Job $job) {
                $job->customer_name = $this->cleanUtf8($job->customer_name);

                if ($job->vehicle) {
                    $job->vehicle->name         = $this->cleanUtf8($job->vehicle->name);
                    $job->vehicle->display_name = $this->cleanUtf8($job->vehicle->display_name ?? '');
                }

                return $job;
            });

        /*
         * RETURNS TODAY
         */
        $this->returnsToday = $this->applyBrandScope(
            Job::query()
                ->whereNotNull('end_at')
                ->whereDate('end_at', $today)
                ->with('vehicle')
                ->orderBy('end_at')
        )
            ->get()
            ->map(function (Job $job) {
                $job->customer_name = $this->cleanUtf8($job->customer_name);

                if ($job->vehicle) {
                    $job->vehicle->name         = $this->cleanUtf8($job->vehicle->name);
                    $job->vehicle->display_name = $this->cleanUtf8($job->vehicle->display_name ?? '');
                }

                return $job;
            });

        /*
         * OPEN TASKS (TODAY + OVERDUE)
         */
        $this->openTasks = $this->baseTaskQuery()
            ->open()
            ->dueTodayOrOverdue()
            ->orderBy('priority')
            ->orderByRaw('due_date IS NULL')
            ->orderBy('due_date')
            ->orderBy('created_at')
            ->get()
            ->map(fn (OpsTask $task) => $this->cleanTask($task));

        /*
         * OVERDUE TASKS
         */
        $this->overdueTasks = $this->baseTaskQuery()
            ->overdue()
            ->orderBy('priority')
            ->orderBy('due_date')
            ->get()
            ->map(fn (OpsTask $task) => $this->cleanTask($task));

        /*
         * COMPLETED TODAY
         */
        $this->completedTodayTasks = $this->baseTaskQuery()
            ->completedToday()
            ->orderByDesc('completed_at')
            ->get()
            ->map(fn (OpsTask $task) => $this->cleanTask($task));

        /*
         * VEHICLES FOR "ADD TASK" DROPDOWN
         */
        $this->vehicles = $this->applyBrandScope(
            Vehicle::query()->orderBy('name')
        )
            ->get()
            ->map(function (Vehicle $vehicle) {
                $vehicle->name         = $this->cleanUtf8($vehicle->name);
                $vehicle->display_name = $this->cleanUtf8($vehicle->display_name ?? '');

                return $vehicle;
            });
    }

    /**
     * Base OpsTask query with all relationships + brand scope.
     */
    protected function baseTaskQuery()
    {
        return OpsTask::query()
            ->with(['vehicle', 'job', 'forUser', 'creator', 'completer'])
            ->forCurrentBrand();
    }

    /**
     * Apply BrandContext scoping to any query that has a brand_id column.
     */
    protected function applyBrandScope($query)
    {
        if (class_exists(\App\Support\BrandContext::class)) {
            $brandId = \App\Support\BrandContext::currentBrandId();

            if ($brandId) {
                $query->where('brand_id', $brandId);
            }
        }

        return $query;
    }

    /**
     * Strip invalid UTF-8 bytes so Livewire/json_encode don't choke.
     */
    protected function cleanUtf8(?string $value): ?string
    {
        if ($value === null) {
            return null;
        }

        return iconv('UTF-8', 'UTF-8//IGNORE', $value) ?: $value;
    }

    protected function cleanTask(OpsTask $task): OpsTask
    {
        $task->title = $this->cleanUtf8($task->title);
        $task->notes = $this->cleanUtf8($task->notes);

        if ($task->vehicle) {
            $task->vehicle->name = $this->cleanUtf8($task->vehicle->name);
        }

        return $task;
    }

    /*
     * ACTIONS
     */

    public function markTaskDone(int $taskId): void
    {
        $task = OpsTask::findOrFail($taskId);

        if (! $task->completed_at) {
            $task->forceFill([
                'completed_at'    => now(),
                'completed_by_id' => auth()->id(),
            ])->save();
        }

        $this->refreshData();
    }

    /**
     * Mark a pickup as done.
     * We store this in job->meta so it persists but doesn't require schema changes.
     */
    public function markPickupDone(int $jobId): void
    {
        /** @var \App\Models\Job $job */
        $job = Job::findOrFail($jobId);

        $meta                          = $job->meta ?? [];
        $meta['ops_pickup_done_at']    = now()->toISOString();
        $meta['ops_pickup_done_by_id'] = auth()->id();

        $job->meta = $meta;
        $job->save();

        $this->refreshData();
    }

    /**
     * Mark a return as done.
     */
    public function markReturnDone(int $jobId): void
    {
        /** @var \App\Models\Job $job */
        $job = Job::findOrFail($jobId);

        $meta                          = $job->meta ?? [];
        $meta['ops_return_done_at']    = now()->toISOString();
        $meta['ops_return_done_by_id'] = auth()->id();

        $job->meta = $meta;
        $job->save();

        $this->refreshData();
    }

    public function createTask(): void
    {
        $this->validate([
            'newTaskTitle'     => ['required', 'string', 'max:255'],
            'newTaskVehicleId' => ['required', 'integer', 'exists:vehicles,id'],
            'newTaskForUserId' => ['nullable', 'integer', 'exists:users,id'],
            'newTaskType'      => ['required', 'string', 'max:50'],
            'newTaskPriority'  => ['required', 'integer', 'between:1,3'],
        ]);

        $brandId = null;
        if (class_exists(\App\Support\BrandContext::class)) {
            $brandId = \App\Support\BrandContext::currentBrandId();
        }

        $cleanTitle = iconv('UTF-8', 'UTF-8//IGNORE', $this->newTaskTitle) ?: $this->newTaskTitle;

        OpsTask::create([
            'title'         => $cleanTitle,
            'vehicle_id'    => $this->newTaskVehicleId,
            'for_user_id'   => $this->newTaskForUserId,
            'type'          => $this->newTaskType,
            'priority'      => $this->newTaskPriority,
            'created_by_id' => auth()->id(),
            'due_date'      => now()->toDateString(),
            'brand_id'      => $brandId,
        ]);

        $this->reset(
            'newTaskTitle',
            'newTaskVehicleId',
            'newTaskForUserId',
            'newTaskType',
            'newTaskPriority'
        );

        $this->newTaskType     = 'other';
        $this->newTaskPriority = 2;

        $this->refreshData();
    }

    /*
     * Helper flags
     */

    public function jobIsOutOnHire(?Job $job): bool
    {
        if (! $job || ! $job->start_at || ! $job->end_at) {
            return false;
        }

        return $job->start_at->isPast() && $job->end_at->isFuture();
    }

    public function jobBondNotCaptured(?Job $job): bool
    {
        // TODO: wire to real deposit/hold logic
        return false;
    }

    public function getJobBondLink(?Job $job): ?string
    {
        return null;
    }
}
