<?php

namespace App\Components\Synapse;

use App\Models\Claim\Claim;
use App\Models\Institution\Institution;
use App\Models\Solicitor\Solicitor;
use App\Models\Synapse\SynapseRun;
use App\Synapse\Agents\DsarTargetIdentifierAgent;
use App\Synapse\Context\DsarContext;
use Illuminate\Support\Facades\Log;
use Livewire\Component;

class DsarIdentifier extends Component
{
    public Claim $claim;

    public bool    $running = false;
    public bool    $ran     = false;
    public ?string $error   = null;
    public ?array  $result  = null;

    public function mount(Claim $claim): void
    {
        $this->claim = $claim;

        $existing = SynapseRun::where('agent_type', 'dsar_identifier')
            ->where('subject_type', Claim::class)
            ->where('subject_id', $claim->id)
            ->whereNotNull('result')
            ->latest()
            ->first();

        if ($existing) {
            $this->result = $existing->result;
            $this->ran    = true;
        }
    }

    public function analyse(): void
    {
        abort_if(!auth()->user()->can('synapse.use'), 403);

        $this->error   = null;
        $this->running = true;
        $this->ran     = false;
        $this->result  = null;

        try {
            $context = DsarContext::fromClaim($this->claim);
            $prompt  = "Analyse the following case data and produce a full DSAR intelligence dataset.\n\n" . $context;

            Log::channel('single')->info('[Synapse:DSAR] Starting analysis', [
                'claim_id'      => $this->claim->id,
                'context_chars' => strlen($context),
            ]);

            $response = (new DsarTargetIdentifierAgent)->prompt($prompt);
            $result   = $response->structured;

            $this->resolveInstitutionIds($result);

            $this->result  = $result;
            $this->ran     = true;
            $this->running = false;

            $targetCount = collect($result['care_setting_reports'] ?? [])
                ->sum(fn ($r) => count($r['dsar_targets'] ?? []));

            Log::channel('single')->info('[Synapse:DSAR] Analysis complete', [
                'claim_id' => $this->claim->id,
                'targets'  => $targetCount,
            ]);

            if (config('synapse.record_runs', true)) {
                SynapseRun::create([
                    'solicitor_id' => app(Solicitor::class)?->id,
                    'user_id'      => auth()->id(),
                    'agent_type'   => 'dsar_identifier',
                    'subject_type' => Claim::class,
                    'subject_id'   => $this->claim->id,
                    'status'       => 'completed',
                    'result'       => $result,
                ]);
            }

        } catch (\Throwable $e) {
            Log::channel('single')->error('[Synapse:DSAR] Exception', [
                'claim_id' => $this->claim->id,
                'message'  => $e->getMessage(),
            ]);
            $this->error   = 'Synapse encountered an error: ' . $e->getMessage();
            $this->running = false;
            report($e);
        }
    }

    private function resolveInstitutionIds(array &$result): void
    {
        if (empty($result['care_setting_reports'])) return;

        $solicitorId = app(Solicitor::class)?->id;
        if (!$solicitorId) return;

        $stopwords = ['the', 'and', 'for', 'with', 'from', 'that', 'this', 'are', 'was', 'its'];

        foreach ($result['care_setting_reports'] as $ri => $report) {
            foreach (($report['dsar_targets'] ?? []) as $ti => $target) {
                $orgName = trim($target['organisation'] ?? '');
                if (!$orgName) continue;

                // Stage 1: full phrase match — exact substring of display_name or alias
                $institution = Institution::with('contacts')
                    ->where('solicitor_id', $solicitorId)
                    ->where(function ($q) use ($orgName) {
                        $q->where('display_name', 'like', "%{$orgName}%")
                          ->orWhereHas('aliases', fn ($a) => $a->where('alias', 'like', "%{$orgName}%"));
                    })
                    ->first();

                // Stage 2: word-level fallback only when phrase match finds nothing
                if (!$institution) {
                    $words = collect(preg_split('/[\s\-\/]+/', strtolower($orgName)))
                        ->map(fn ($w) => preg_replace('/[^a-z0-9]/', '', $w))
                        ->filter(fn ($w) => strlen($w) >= 3 && !in_array($w, $stopwords))
                        ->unique()->values()->all();

                    if (!empty($words)) {
                        $minMatches = max(2, (int) ceil(count($words) * 0.75));

                        $best = Institution::with('contacts')
                            ->where('solicitor_id', $solicitorId)
                            ->where(function ($q) use ($words) {
                                foreach ($words as $word) {
                                    $q->orWhere('display_name', 'like', "%{$word}%")
                                      ->orWhereHas('aliases', fn ($a) => $a->where('alias', 'like', "%{$word}%"));
                                }
                            })
                            ->limit(50)
                            ->get()
                            ->map(function (Institution $inst) use ($words) {
                                $name = strtolower($inst->display_name);
                                $score = collect($words)
                                    ->filter(fn ($w) => str_contains($name, $w))
                                    ->count();
                                return ['institution' => $inst, 'score' => $score];
                            })
                            ->sortByDesc('score')
                            ->first();

                        if ($best && $best['score'] >= $minMatches) {
                            $institution = $best['institution'];
                        }
                    }
                }

                Log::channel('single')->info('[Synapse:DSAR] Institution resolution', [
                    'organisation' => $orgName,
                    'resolved_to'  => $institution?->display_name,
                    'resolved_id'  => $institution?->id,
                ]);

                if ($institution) {
                    $result['care_setting_reports'][$ri]['dsar_targets'][$ti]['institution_id'] = $institution->id;
                    $result['care_setting_reports'][$ri]['dsar_targets'][$ti]['contact_in_db']  = $institution->contacts->isNotEmpty();
                }
            }
        }
    }

    public function render(): \Illuminate\View\View
    {
        return view('components.synapse.dsar-identifier');
    }
}
