<?php

namespace App\Console\Commands;

use App\Enum\Dsar\DsarStatus;
use App\Models\Client\Client;
use App\Models\Claim\Claim;
use App\Models\Dsar\Dsar;
use App\Models\Dsar\DsarTranche;
use App\Models\Dsar\DsarType;
use App\Models\Institution\Institution;
use App\Models\Institution\InstitutionAlias;
use App\Models\Solicitor\Solicitor;
use App\Models\User\User;
use Illuminate\Console\Command;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class SeedInboxDsars extends Command
{
    protected $signature = 'inbox:seed-dsars
                            {--solicitor=   : Solicitor ID to seed for; omit to pick interactively}
                            {--count=1      : Number of DSARs to create per institution}
                            {--fresh        : Delete all open DSARs previously seeded for these institutions before creating new ones}';

    protected $description = 'Seed fake open DSARs for NHS/care institutions so the DsarMatcherAgent can match inbound emails';

    /**
     * Institution definitions that mirror the sender names used in inbox:fake --seed.
     *
     * display_name  → what is stored in institutions.display_name (searchable by the AI tool)
     * alias         → alternative name to register in institution_aliases
     * domain        → email domain the fake emails arrive from
     */
    private array $seedInstitutions = [
        [
            'display_name' => 'NHS Lothian',
            'alias'        => 'NHS Lothian Records Team',
            'domain'       => 'nhslothian.scot.nhs.uk',
        ],
        [
            'display_name' => 'County Durham and Darlington NHS Foundation Trust',
            'alias'        => 'County Durham & Darlington NHS FT',
            'domain'       => 'cddft.nhs.uk',
        ],
        [
            'display_name' => 'Bupa UK',
            'alias'        => 'Bupa UK Information Governance',
            'domain'       => 'bupa.com',
        ],
        [
            'display_name' => 'Care UK',
            'alias'        => 'Care UK Data Requests',
            'domain'       => 'careuk.com',
        ],
        [
            'display_name' => 'HC-One',
            'alias'        => 'HC-One Subject Access Team',
            'domain'       => 'hc-one.co.uk',
        ],
        [
            'display_name' => 'Four Seasons Health Care',
            'alias'        => 'Four Seasons Health Care SAR Team',
            'domain'       => 'fshc.co.uk',
        ],
        [
            'display_name' => 'Priory Group',
            'alias'        => 'Priory Group Information Rights',
            'domain'       => 'priorygroup.com',
        ],
        [
            'display_name' => 'Barchester Healthcare',
            'alias'        => 'Barchester Healthcare SAR Team',
            'domain'       => 'barchester.com',
        ],
        [
            'display_name' => 'NHS Greater Manchester Integrated Care Board',
            'alias'        => 'NHS Greater Manchester ICB',
            'domain'       => 'greatermanchester.nhs.uk',
        ],
        [
            'display_name' => 'Tameside and Glossop Integrated Care NHS Foundation Trust',
            'alias'        => 'Tameside & Glossop Integrated Care',
            'domain'       => 'tamesideglossop.nhs.uk',
        ],
        [
            'display_name' => 'Doncaster and Bassetlaw Teaching Hospitals NHS Foundation Trust',
            'alias'        => 'Doncaster & Bassetlaw Teaching Hospitals',
            'domain'       => 'dbth.nhs.uk',
        ],
        [
            'display_name' => 'Blackpool Teaching Hospitals NHS Foundation Trust',
            'alias'        => 'Blackpool Teaching Hospitals',
            'domain'       => 'bfwh.nhs.uk',
        ],
        [
            'display_name' => 'Mid Cheshire Hospitals NHS Foundation Trust',
            'alias'        => 'Mid Cheshire Hospitals NHS FT',
            'domain'       => 'mcht.nhs.uk',
        ],
        [
            'display_name' => 'University Hospitals Coventry and Warwickshire NHS Trust',
            'alias'        => 'University Hospitals Coventry',
            'domain'       => 'uhcw.nhs.uk',
        ],
    ];

    // ── Handle ────────────────────────────────────────────────────────────────

    public function handle(): int
    {
        $count = max(1, (int) $this->option('count'));
        $fresh = $this->option('fresh');

        // ── Resolve solicitor ──────────────────────────────────────────────
        $solicitor = $this->resolveSolicitor();
        if (!$solicitor) {
            return self::FAILURE;
        }

        $solicitorId = $solicitor->id;

        // ── Resolve user (needed for Dsar.user_id) ─────────────────────────
        // Prefer a user belonging to the solicitor; fall back to any user (platform admins).
        $user = User::where('solicitor_id', $solicitorId)->first()
             ?? User::first();

        if (!$user) {
            $this->error('No users found in the database. Seed users first.');
            return self::FAILURE;
        }

        // ── Resolve DsarType (use first available) ─────────────────────────
        $dsarTypeId = DsarType::withoutGlobalScopes()->value('id');

        // ── Claim status (always 1 = active/open) ──────────────────────────
        $claimStatusId = DB::table('statuses')->value('id') ?? 1;

        $this->line('');
        $this->line("  <info>→</info> Solicitor: <comment>{$solicitor->name}</comment> (ID #{$solicitorId})");
        $this->line("  <info>→</info> Creating <comment>{$count}</comment> DSAR(s) per institution across <comment>" . count($this->seedInstitutions) . "</comment> institutions");
        $this->line('');

        $totalDsars   = 0;
        $createdInst  = 0;
        $rows         = [];

        foreach ($this->seedInstitutions as $def) {
            // ── Find or create Institution ─────────────────────────────────
            [$institution, $isNew] = $this->findOrCreateInstitution($def, $solicitorId, $dsarTypeId);

            if ($isNew) {
                $createdInst++;
                $this->line("  <info>+</info> Created institution: <comment>{$institution->display_name}</comment>");
            } else {
                $this->line("  <comment>~</comment> Using existing institution: <comment>{$institution->display_name}</comment>");
            }

            // ── Optionally wipe existing open DSARs for this institution ───
            if ($fresh) {
                $deleted = Dsar::withoutGlobalScopes()
                    ->where('solicitor_id', $solicitorId)
                    ->where('institution_id', $institution->id)
                    ->whereNotIn('status', DsarStatus::excludedFromOpen())
                    ->forceDelete();

                if ($deleted > 0) {
                    $this->line("    <comment>✗</comment> Deleted {$deleted} existing open DSAR(s)");
                }
            }

            // ── Create DSARs ───────────────────────────────────────────────
            for ($i = 0; $i < $count; $i++) {
                $dsar = $this->createDsar($solicitorId, $user->id, $institution->id, $claimStatusId, $def['display_name']);

                $rows[]      = [$institution->display_name, substr($dsar->slug, 0, 8) . '…', $dsar->status];
                $totalDsars++;
            }
        }

        $this->newLine();
        $this->info("✓ Done — created {$totalDsars} open DSAR(s) across " . count($this->seedInstitutions) . " institutions");
        $this->line("  {$createdInst} new institution(s) created");
        $this->newLine();

        $this->table(
            ['Institution', 'DSAR Slug (prefix)', 'Status'],
            $rows,
        );

        $this->newLine();
        $this->line('  Now run: <comment>php artisan inbox:fake --seed --count=20 --spread --classify</comment>');
        $this->line('  Then:    <comment>php artisan queue:work</comment>');

        return self::SUCCESS;
    }

    // ── Helpers ───────────────────────────────────────────────────────────────

    private function resolveSolicitor(): ?Solicitor
    {
        $idOpt = $this->option('solicitor');

        $all = Solicitor::all();

        if ($all->isEmpty()) {
            $this->error('No solicitors found in the database.');
            return null;
        }

        if ($idOpt) {
            $s = $all->firstWhere('id', (int) $idOpt);
            if (!$s) {
                $this->error("No solicitor found with ID: {$idOpt}");
                return null;
            }
            return $s;
        }

        if ($all->count() === 1) {
            return $all->first();
        }

        $choices = $all->mapWithKeys(fn ($s) => [
            $s->id => "#{$s->id} — {$s->name}",
        ])->all();

        $chosen = $this->choice('Which solicitor should the DSARs belong to?', array_values($choices));
        $id     = array_search($chosen, $choices);

        return $all->firstWhere('id', $id);
    }

    /**
     * Find an existing institution with a matching display_name for this solicitor,
     * or create a new one and register its alias.
     *
     * @return array{Institution, bool}  [institution, $wasCreated]
     */
    private function findOrCreateInstitution(array $def, int $solicitorId, ?int $dsarTypeId): array
    {
        $displayName = $def['display_name'];
        $alias       = $def['alias'];

        // Search: exact display_name match first, then alias match
        $institution = Institution::withoutGlobalScopes()
            ->where('solicitor_id', $solicitorId)
            ->where(function ($q) use ($displayName, $alias) {
                $q->where('display_name', $displayName)
                  ->orWhereHas('aliases', fn ($a) => $a->where('alias', $displayName))
                  ->orWhereHas('aliases', fn ($a) => $a->where('alias', $alias));
            })
            ->first();

        if ($institution) {
            // Ensure the alias exists so the AI tool can find it by both names
            $this->ensureAlias($institution, $alias, $solicitorId);
            return [$institution, false];
        }

        // Create new institution
        $institution = Institution::withoutGlobalScopes()->create([
            'solicitor_id'  => $solicitorId,
            'display_name'  => $displayName,
            'dsar_type_id'  => $dsarTypeId,
            'send_type'     => 'email',
            'is_prioritised' => false,
        ]);

        // Register alias (alternative / abbreviated name used in email display names)
        if ($alias !== $displayName) {
            InstitutionAlias::create([
                'solicitor_id'   => $solicitorId,
                'institution_id' => $institution->id,
                'alias'          => $alias,
            ]);
        }

        return [$institution, true];
    }

    private function ensureAlias(Institution $institution, string $alias, int $solicitorId): void
    {
        $exists = InstitutionAlias::withoutGlobalScopes()
            ->where('institution_id', $institution->id)
            ->where('alias', $alias)
            ->exists();

        if (!$exists) {
            InstitutionAlias::create([
                'solicitor_id'   => $solicitorId,
                'institution_id' => $institution->id,
                'alias'          => $alias,
            ]);
        }
    }

    private function createDsar(
        int    $solicitorId,
        int    $userId,
        int    $institutionId,
        int    $claimStatusId,
        string $institutionName
    ): Dsar {
        // Client ── use factory to satisfy FK/cast requirements cleanly
        $client = Client::factory()->create(['solicitor_id' => $solicitorId]);

        // Claim
        $claim = Claim::withoutGlobalScopes()->create([
            'solicitor_id' => $solicitorId,
            'client_id'    => $client->id,
            'status_id'    => $claimStatusId,
            'redress_type' => 'FIXED',
        ]);

        // DsarTranche
        $tranche = DsarTranche::withoutGlobalScopes()->create([
            'solicitor_id' => $solicitorId,
            'claim_id'     => $claim->id,
            'status'       => 'sent',
        ]);

        // Timestamps: sent 30-90 days ago, expected 1-month statutory window
        $postedAt   = now()->subDays(rand(30, 90));
        $expectedAt = $postedAt->copy()->addDays(30);

        // Dsar (slug auto-generated by HasSlug on creating event)
        $dsar = Dsar::withoutGlobalScopes()->create([
            'solicitor_id'  => $solicitorId,
            'user_id'       => $userId,
            'institution_id' => $institutionId,
            'claim_id'      => $claim->id,
            'tranche_id'    => $tranche->id,
            'status'        => 'sent',
            'is_flagged'    => false,
            'posted_at'     => $postedAt,
            'expected_at'   => $expectedAt,
            'content'       => $this->dsarContent($client, $institutionName),
        ]);

        return $dsar;
    }

    private function dsarContent(Client $client, string $institutionName): string
    {
        $name = trim("{$client->name_first} {$client->name_last}");
        $dob  = $client->date_of_birth;
        $dobStr = $dob ? (is_string($dob) ? $dob : $dob->format('d/m/Y')) : 'unknown';

        return <<<TEXT
        Dear Data Protection Officer,

        We act as solicitors for {$name} (date of birth: {$dobStr}) and write to request, pursuant to Article 15 of the UK General Data Protection Regulation and Section 45 of the Data Protection Act 2018, that you provide us with all personal data held by {$institutionName} relating to our client.

        Specifically, we request copies of all medical records, care records, correspondence, notes, and any other personal data held in whatever format, including electronically, relating to the above individual during all periods of treatment or residency.

        We look forward to your response within one calendar month of receipt of this request as required by law.

        Yours faithfully,
        [Solicitor]
        TEXT;
    }
}
