<?php

namespace App\Components\Claim\Application;

use App\Models\Claim\Area;
use App\Models\Claim\Claim;
use App\Models\Claim\Council;
use App\Models\Dsar\DsarType;
use App\Models\Institution\Institution;
use App\Models\Institution\InstitutionType;
use App\Services\HistoryService;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Str;
use Livewire\Component;
use Livewire\WithFileUploads;
use Illuminate\Validation\ValidationException;

class CareSettingManager extends Component {
    use AuthorizesRequests;
    use WithFileUploads;

    public Claim $claim;

    public $settings = [];

    public $institutionTypes = [];

    /** Councils for the Local Authority select (also used to narrow area search). */
    public $councils = [];

    // Modal State Variables
    public $isModalOpen = false;
    public $newInstitutionName = '';
    public $activeSettingIndex = null;

    public function mount(Claim $claim)
    {
        $this->claim = $claim;
        $this->institutionTypes = InstitutionType::all();
        $this->councils = Council::orderBy('name')->get(['id', 'name'])->toArray();

        $this->claim->loadMissing('careSettings.area.council');

        foreach ($this->claim->careSettings as $setting) {
            $this->settings[] = [
                'id' => $setting->id,
                '_ui_key' => 'existing_' . $setting->id,
                'institution_id' => $setting->institution_id,
                'institution_name' => $setting->institution->display_name,
                'institution_type_id' => $setting->institution->type_id,
                'area_id' => $setting->area_id,
                'area_name' => $setting->area?->name ?? '',
                'council_id' => $setting->area?->council_id,
                'local_authority' => $setting->area?->council?->name ?? '',
                'area_search_results' => [],
                'date_text' => $setting->dates,
                'people_involved' => $setting->people_involved,
                'search_results' => [],
            ];
        }
    }

    public function addSetting()
    {
        $this->settings[] = [
            'id' => null,
            '_ui_key' => 'new_' . Str::random(8),
            'institution_id' => null,
            'institution_name' => '',
            'institution_type_id' => null,
            'area_id' => null,
            'area_name' => '',
            'council_id' => null,
            'local_authority' => '',
            'area_search_results' => [],
            'date_text' => '',
            'people_involved' => '',
            'search_results' => [],
        ];
    }

    public function removeSetting(HistoryService $history, $index)
    {
        $this->authorize('claims.edit');
        $setting = $this->settings[$index];
        if ($setting['id']) {
            $this->claim->careSettings()->where('id', $setting['id'])->delete();

            $history->add($this->claim->client, 'Care setting "' . $setting['institution_name'] . '" removed', [
                'claim_id'        => $this->claim->id,
                'care_setting_id' => $setting['id'],
                'institution'     => $setting['institution_name'],
            ]);
        }
        unset($this->settings[$index]);
        $this->settings = array_values($this->settings);
    }

    public function search($index) {
        $this->settings[$index]['search_results'] = [];

        if ($this->settings[$index]['institution_id']) {
            return;
        }

        $term = trim($this->settings[$index]['institution_name']);
        if (strlen($term) < 2) {
            return;
        }

        $this->settings[$index]['search_results'] = Institution::where('display_name', 'like', '%' . $term . '%')
            ->orWhereHas('aliases', function ($query) use ($term) {
                $query->where('alias', 'like', '%' . $term . '%');
            })
            ->with('aliases')
            ->limit(10)
            ->get()
            ->map(function ($institution) use ($term) {
                $data = $institution->toArray();

                $nameMatches = stripos($institution->display_name, $term) !== false;

                if (!$nameMatches) {
                    $matchingAlias = $institution->aliases
                        ->first(fn($a) => stripos($a->alias, $term) !== false);

                    if ($matchingAlias) {
                        $data['display_name'] = "{$institution->display_name} ({$matchingAlias->alias})";
                    }
                }

                return $data;
            })
            ->values()
            ->toArray();
    }

    public function setItem($index, $institutionId) {
        $inst = Institution::with('area.council')->find($institutionId);
        if ($inst) {
            $this->settings[$index]['institution_id'] = $inst->id;
            $this->settings[$index]['institution_name'] = $inst->display_name;
            $this->settings[$index]['institution_type_id'] = $inst->type_id;
            $this->settings[$index]['search_results'] = [];

            // Prefill area + local authority from the institution's canonical
            // location, but never clobber an area already chosen for this setting.
            if ($inst->area_id && empty($this->settings[$index]['area_id'])) {
                $this->settings[$index]['area_id'] = $inst->area_id;
                $this->settings[$index]['area_name'] = $inst->area?->name ?? '';
                $this->settings[$index]['council_id'] = $inst->area?->council_id;
                $this->settings[$index]['local_authority'] = $inst->area?->council?->name ?? '';
            }
        }
    }

    public function clearItem($index) {
        $this->settings[$index]['institution_id'] = null;
        $this->settings[$index]['institution_name'] = '';
        $this->settings[$index]['search_results'] = [];
    }

    /**
     * Search areas by name for a setting, optionally narrowed to the council
     * chosen in the Local Authority filter. Results carry their council so the
     * handler can disambiguate names that exist under more than one council.
     */
    public function searchArea($index) {
        $this->settings[$index]['area_search_results'] = [];

        if ($this->settings[$index]['area_id']) {
            return;
        }

        $term = trim($this->settings[$index]['area_name']);
        if (strlen($term) < 2) {
            return;
        }

        $query = Area::query()->with('council')->where('name', 'like', '%' . $term . '%');

        if ($this->settings[$index]['council_id']) {
            $query->where('council_id', $this->settings[$index]['council_id']);
        }

        $this->settings[$index]['area_search_results'] = $query->orderBy('name')->limit(10)->get()
            ->map(fn (Area $a) => ['id' => $a->id, 'name' => $a->name, 'council' => $a->council?->name])
            ->values()->toArray();
    }

    /** Select an area — this fixes the Local Authority to the area's council. */
    public function setArea($index, $areaId) {
        $area = Area::with('council')->find($areaId);
        if ($area) {
            $this->settings[$index]['area_id'] = $area->id;
            $this->settings[$index]['area_name'] = $area->name;
            $this->settings[$index]['council_id'] = $area->council_id;
            $this->settings[$index]['local_authority'] = $area->council?->name ?? '';
            $this->settings[$index]['area_search_results'] = [];
        }
    }

    /** Clear the chosen area (leaving any council filter in place). */
    public function clearArea($index) {
        $this->settings[$index]['area_id'] = null;
        $this->settings[$index]['area_name'] = '';
        $this->settings[$index]['local_authority'] = '';
        $this->settings[$index]['area_search_results'] = [];
    }

    public function openModal($index) {
        $this->activeSettingIndex = $index;
        $this->newInstitutionName = $this->settings[$index]['institution_name'];
        $this->isModalOpen = true;
    }

    public function closeModal() {
        $this->isModalOpen = false;
        $this->newInstitutionName = '';
        $this->activeSettingIndex = null;
    }

    public function saveNewInstitution() {
        $this->authorize('claims.edit');
        $this->validate([
            'newInstitutionName' => 'required|string|min:3|max:255',
        ]);

        $institution = Institution::create([
            'display_name' => $this->newInstitutionName,
            'dsar_type_id' => DsarType::first()->id ?? null,
        ]);

        if ($this->activeSettingIndex !== null) {
            $this->setItem($this->activeSettingIndex, $institution->id);
        }

        $this->closeModal();
    }

    public function save(HistoryService $history)
    {
        $this->authorize('claims.edit');
        try {
            $this->validate([
                'settings.*.institution_id' => 'required|exists:institutions,id',
                'settings.*.area_id' => 'nullable|exists:areas,id',
                'settings.*.date_text' => 'required|string',
                'settings.*.people_involved' => 'nullable|string',
            ], [
                'settings.*.institution_id.required' => 'Please select an institution.',
                'settings.*.date_text.required' => 'Please provide the dates.',
            ]);

            \DB::transaction(function () {
                foreach ($this->settings as $index => $setting) {
                    $careSetting = $this->claim->careSettings()->updateOrCreate(
                        ['id' => $setting['id'] ?? null],
                        [
                            'institution_id'  => $setting['institution_id'],
                            'area_id'         => $setting['area_id'] ?? null,
                            'dates'           => $setting['date_text'],
                            'people_involved' => $setting['people_involved'],
                        ]
                    );

                    $this->settings[$index]['id'] = $careSetting->id;

                    if (str_starts_with($setting['_ui_key'], 'new_')) {
                        $this->settings[$index]['_ui_key'] = 'existing_' . $careSetting->id;
                    }
                }
            });

            $history->add($this->claim->client, count($this->settings) . ' care setting(s) saved', [
                'claim_id' => $this->claim->id,
                'count'    => count($this->settings),
            ]);

            $this->dispatch(
                'toast',
                type: 'success',
                message: 'Care settings saved successfully.'
            );

        } catch (ValidationException $e) {
            $this->dispatch(
                'toast',
                type: 'error',
                message: $e->getMessage()
            );
            throw $e;
        } catch (\Exception $e) {
            $this->dispatch(
                'toast',
                type: 'error',
                message: 'An unexpected error occurred while saving.'
            );
        }
    }

    public function render() {
        return view('components.claim.application.care-setting-manager');
    }
}