<?php

namespace App\Http\Controllers;

use App\Models\Activity;
use App\Models\Contract;
use App\Models\FieldJob;
use App\Models\FieldJobSetting;
use App\Models\User;
use Exception;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;

class FieldJobController extends Controller
{
    public function index(Request $request)
    {
        $setting = FieldJobSetting::query()->latest('id')->first();
        // Only fetch contracts that are currently in either the primary segment
        // or the optional queue segment defined on the latest FieldJobSetting.
        $segmentIds = collect([
            optional($setting)->queue_segment_id,
            optional($setting)->segment_id,
        ])->filter()->unique()->values();

        $search = $request->input('search');
        $searchAssigned = $request->input('search_assigned');
        $assignedUserId = $request->input('assigned_user_id');
        $unassignedClientUuids = $request->input('unassigned_client_uuids');
        $assignedClientUuids = $request->input('assigned_client_uuids');

        $unassignedContracts = Contract::query()
            ->with(['clientCase.person.addresses', 'clientCase.client.person:id,uuid,full_name', 'type', 'account'])
            ->when($segmentIds->isNotEmpty(), fn($q) => 
                $q->whereHas('segments', fn($rq) => $rq->whereIn('segments.id', $segmentIds)),
                fn($q) => $q->whereRaw('1 = 0')
            )
            ->when( !empty($search), fn ($q) => 
                $q->where(fn($sq) => 
                    $sq->where('reference', 'like', "%{$search}%")
                        ->orWhereHas('clientCase.person', fn($psq) => 
                            $psq->where('full_name', 'ilike', "%{$search}%")
                        )
                        ->orWhereHas('clientCase.person.addresses', fn ($ccpaq) =>
                            $ccpaq->where('address', 'ilike', "%{$search}")
                        )
                )
            )
            ->when(!empty($unassignedClientUuids) && is_array($unassignedClientUuids), fn ($q) =>
                $q->whereHas('clientCase.client', fn($cq) => 
                    $cq->whereIn('uuid', $unassignedClientUuids)
                )
            )
            ->whereDoesntHave('fieldJobs', fn ($q) => 
                $q->whereNull('completed_at')
                  ->whereNull('cancelled_at')
            )
            ->latest('id');

        $unassignedClients = $unassignedContracts->get()
            ->pluck('clientCase.client')
            ->filter()
            ->unique('id')
            ->values();
        

        $assignedContracts = Contract::query()
            ->with(['clientCase.person.addresses', 'clientCase.client.person:id,uuid,full_name', 'type', 'account', 'lastFieldJobs', 'lastFieldJobs.assignedUser', 'lastFieldJobs.user'])
            ->when($segmentIds->isNotEmpty(), fn($q) => 
                $q->whereHas('segments', fn($rq) => $rq->whereIn('segments.id', $segmentIds)),
                fn($q) => $q->whereRaw('1 = 0')
            )
            ->when( !empty($searchAssigned), fn ($q) => 
                $q->where(fn($sq) => 
                    $sq->where('reference', 'like', "%{$searchAssigned}%")
                        ->orWhereHas('clientCase.person', fn($psq) => 
                            $psq->where('full_name', 'ilike', "%{$searchAssigned}%")
                        )
                        ->orWhereHas('clientCase.person.addresses', fn ($ccpaq) =>
                            $ccpaq->where('address', 'ilike', "%{$searchAssigned}")
                        )
                )
            )
            ->when(!empty($assignedClientUuids) && is_array($assignedClientUuids), fn ($q) =>
                $q->whereHas('clientCase.client', fn($cq) => 
                    $cq->whereIn('uuid', $assignedClientUuids)
                )
            )
            ->whereHas('lastFieldJobs', fn ($q) => 
                $q->whereNull('completed_at')
                  ->whereNull('cancelled_at')
                  ->when($assignedUserId && $assignedUserId !== 'all', fn ($jq) => 
                    $jq->where('assigned_user_id', $assignedUserId))
            )
            ->latest('id');

        $assignedClients = $assignedContracts->get()
            ->pluck('clientCase.client')
            ->filter()
            ->unique('id')
            ->values();

        $users = User::query()->orderBy('name')->get(['id', 'name']);

        return Inertia::render('FieldJob/Index', [
            'setting' => $setting,
            'unassignedContracts' => $unassignedContracts->paginate(
                    $request->input('per_page_contracts', 10),
                    ['*'],
                    'page_contracts',
                    $request->input('page_contracts', 1)
                ),
            'assignedContracts' => $assignedContracts->paginate(
                $request->input('per_page_assignments', 10),
                ['*'],
                'page_assignments',
                $request->input('page_assignments', 1)
            ),
            'unassignedClients' => $unassignedClients,
            'assignedClients' => $assignedClients,
            'users' => $users,
            'filters' => [
                'search' => $search,
                'search_assigned' => $searchAssigned,
                'assigned_user_id' => $assignedUserId,
                'unassigned_client_uuids' => $unassignedClientUuids,
                'assigned_client_uuids' => $assignedClientUuids,
            ],
        ]);
    }

    public function assign(Request $request)
    {
        $data = $request->validate([
            'contract_uuid' => 'required|string|exists:contracts,uuid',
            'assigned_user_id' => 'required|integer|exists:users,id',
        ]);

        try {
            DB::transaction(function () use ($data) {
                $setting = FieldJobSetting::query()->latest('id')->first();

                if (! $setting) {
                    throw new Exception('No Field Job Setting found. Create one in Settings → Field Job Settings.');
                }

                $contract = Contract::query()->where('uuid', $data['contract_uuid'])->firstOrFail();

                $job = FieldJob::create([
                    'field_job_setting_id' => $setting->id,
                    'assigned_user_id' => $data['assigned_user_id'],
                    'contract_id' => $contract->id,
                    'assigned_at' => now(),
                ]);
                // Create an activity for the assignment
                if ($setting->action_id && $setting->assign_decision_id) {
                    $assigneeName = User::query()->where('id', $data['assigned_user_id'])->value('name');
                    // Localized note: "Terensko opravilo dodeljeno" + assignee when present
                    $note = 'Terensko opravilo dodeljeno'.($assigneeName ? ' uporabniku '.$assigneeName : '');
                    Activity::create([
                        'due_date' => null,
                        'amount' => null,
                        'note' => $note,
                        'action_id' => $setting->action_id,
                        'decision_id' => $setting->assign_decision_id,
                        'client_case_id' => $contract->client_case_id,
                        'contract_id' => $contract->id,
                    ]);

                    // Move contract to the configured segment for field jobs
                    $job->moveContractToSegment($setting->segment_id);
                } else {
                    throw new Exception('The current Field Job Setting is missing an action or assign decision. Please update it in Settings → Field Job Settings.');
                }
            });

            return back()->with('success', 'Field job assigned.');
        } catch (QueryException $e) {
            return back()->withErrors(['database' => 'Database error: '.$e->getMessage()]);
        } catch (Exception $e) {
            return back()->withErrors(['error' => 'Error: '.$e->getMessage()]);
        }

    }

    /**
     * Bulk assign multiple contracts to a single user.
     */
    public function assignBulk(Request $request)
    {
        $data = $request->validate([
            'contract_uuids' => 'required|array|min:1',
            'contract_uuids.*' => 'required|string|distinct|exists:contracts,uuid',
            'assigned_user_id' => 'required|integer|exists:users,id',
        ]);

        try {
            DB::transaction(function () use ($data) {
                $setting = FieldJobSetting::query()->latest('id')->first();

                if (! $setting) {
                    throw new Exception('No Field Job Setting found. Create one in Settings → Field Job Settings.');
                }

                if (! ($setting->action_id && $setting->assign_decision_id)) {
                    throw new Exception('The current Field Job Setting is missing an action or assign decision. Please update it in Settings → Field Job Settings.');
                }

                $assigneeName = User::query()->where('id', $data['assigned_user_id'])->value('name');
                $noteBase = 'Terensko opravilo dodeljeno'.($assigneeName ? ' uporabniku '.$assigneeName : '');

                // Load all contracts in one query
                $contracts = Contract::query()->whereIn('uuid', $data['contract_uuids'])->get();

                foreach ($contracts as $contract) {
                    // Skip if already has an active job
                    $hasActive = FieldJob::query()
                        ->where('contract_id', $contract->id)
                        ->whereNull('completed_at')
                        ->whereNull('cancelled_at')
                        ->exists();

                    if ($hasActive) {
                        continue;
                    }

                    $job = FieldJob::create([
                        'field_job_setting_id' => $setting->id,
                        'assigned_user_id' => $data['assigned_user_id'],
                        'contract_id' => $contract->id,
                        'assigned_at' => now(),
                    ]);

                    Activity::create([
                        'due_date' => null,
                        'amount' => null,
                        'note' => $noteBase,
                        'action_id' => $setting->action_id,
                        'decision_id' => $setting->assign_decision_id,
                        'client_case_id' => $contract->client_case_id,
                        'contract_id' => $contract->id,
                    ]);

                    // Move contract to the configured segment for field jobs
                    $job->moveContractToSegment($setting->segment_id);
                }
            });

            return back()->with('success', 'Field jobs assigned.');
        } catch (QueryException $e) {
            return back()->withErrors(['database' => 'Database error: '.$e->getMessage()]);
        } catch (Exception $e) {
            return back()->withErrors(['error' => 'Error: '.$e->getMessage()]);
        }
    }

    public function cancel(Request $request)
    {
        $data = $request->validate([
            'contract_uuid' => 'required|string|exists:contracts,uuid',
        ]);

        $contract = Contract::query()->where('uuid', $data['contract_uuid'])->firstOrFail();

        $job = FieldJob::query()
            ->where('contract_id', $contract->id)
            ->whereNull('completed_at')
            ->whereNull('cancelled_at')
            ->latest('id')
            ->first();

        if ($job) {
            $job->cancelled_at = now();
            $job->save();

            // Create an activity for the cancellation, mirroring the assign flow
            // Prefer the job's setting for a consistent decision
            $job->loadMissing('setting');
            $actionId = optional($job->setting)->action_id;
            $decisionId = optional($job->setting)->cancel_decision_id;

            // If no decision configured, skip logging
            if ($actionId && $decisionId) {

                Activity::create([
                    'due_date' => null,
                    'amount' => null,
                    'note' => 'Terensko opravilo preklicano',
                    'action_id' => $actionId,
                    'decision_id' => $decisionId,
                    'client_case_id' => $contract->client_case_id,
                    'contract_id' => $contract->id,
                ]);

            }
        }

        return back()->with('success', 'Field job cancelled.');
    }

    public function complete(Request $request, \App\Models\ClientCase $clientCase)
    {
        // Complete all active field jobs for contracts of this case assigned to current user
        $userId = optional($request->user())->id;
        $setting = FieldJobSetting::query()->latest('id')->first();
        if (! $setting) {
            return back()->withErrors(['setting' => 'No Field Job Setting found.']);
        }

        $decisionId = $setting->complete_decision_id;
        $actionId = $setting->action_id;

        // Find all active jobs for this case for the current user
        $jobs = FieldJob::query()
            ->whereHas('contract', function ($q) use ($clientCase) {
                $q->where('client_case_id', $clientCase->id);
            })
            ->where(function ($q) use ($userId) {
                if ($userId) {
                    $q->where('assigned_user_id', $userId);
                }
            })
            ->whereNull('completed_at')
            ->whereNull('cancelled_at')
            ->with(['contract:id,client_case_id', 'setting'])
            ->get();

        DB::transaction(function () use ($jobs, $decisionId, $actionId) {
            foreach ($jobs as $job) {
                // Mark job complete
                $job->completed_at = now();
                $job->save();

                // Log completion activity on the contract/case
                if ($actionId && $decisionId) {
                    Activity::create([
                        'due_date' => null,
                        'amount' => null,
                        'note' => 'Terensko opravilo zaključeno',
                        'action_id' => $actionId,
                        'decision_id' => $decisionId,
                        'client_case_id' => $job->contract->client_case_id,
                        'contract_id' => $job->contract_id,
                    ]);
                }

                // Move contract to configured return segment
                $job->returnContractToConfiguredSegment();
            }
        });

        // Redirect back to phone index
        return to_route('phone.index');
    }
}
