<?php

namespace Database\Seeders;

use App\Models\Claim\Status;
use App\Models\PensionCase\PensionCase;
use Illuminate\Database\Seeder;
use Illuminate\Support\Collection;

/**
 * Backfills claim_type and status_id on existing pension_cases rows
 * using the legacy string columns: bank_claim_status, fos_claim_status, fscs_claim_status.
 *
 * Priority when multiple columns are populated: fscs > fos > bank.
 *
 * Run after PensionStatusSeeder so the statuses table is populated.
 *   php artisan db:seed --class=PensionCaseMigrateStatusSeeder
 */
class PensionCaseMigrateStatusSeeder extends Seeder
{
    // Map claim_type → legacy column name
    private array $typeColumn = [
        'fscs' => 'fscs_claim_status',
        'fos'  => 'fos_claim_status',
        'bank' => 'bank_claim_status',
    ];

    public function run(): void
    {
        // Pre-load all pension statuses into memory, keyed by type → normalised name → id
        $statusMap = $this->buildStatusMap();

        $updated   = 0;
        $skipped   = 0;   // already has claim_type
        $noValue   = 0;   // all three columns empty
        $unmatched = [];  // status strings we couldn't resolve

        // Process in chunks to handle thousands of rows without memory issues
        PensionCase::query()
            ->chunkById(200, function (Collection $cases) use (
                $statusMap, &$updated, &$skipped, &$noValue, &$unmatched
            ) {
                foreach ($cases as $case) {
                    $resolved = $this->resolveCase($case, $statusMap);

                    if ($resolved === null) {
                        $noValue++;
                        continue;
                    }

                    [$claimType, $statusId, $rawValue] = $resolved;

                    if ($statusId === null) {
                        $unmatched[] = "[{$claimType}] \"{$rawValue}\" (case #{$case->id})";
                    }

                    $case->timestamps = false; // don't bump updated_at
                    $case->update([
                        'claim_type' => $claimType,
                        'status_id'  => $statusId,
                    ]);

                    $updated++;
                }
            });

        // Also skip rows that already have claim_type set
        $skipped = PensionCase::whereNotNull('claim_type')->count() - $updated;

        $this->command->info("Updated : {$updated}");
        $this->command->info("No value: {$noValue} (all three status columns empty — left as-is)");

        if ($unmatched) {
            $this->command->warn(count($unmatched) . ' status string(s) could not be matched to a seeded status:');
            foreach ($unmatched as $line) {
                $this->command->warn("  → {$line}");
            }
            $this->command->warn('These rows have claim_type set but status_id is NULL. Fix via the admin UI.');
        } else {
            $this->command->info('All status strings matched successfully.');
        }
    }

    /**
     * Determine claim_type and status_id for a single case.
     * Returns [claimType, statusId, rawValue] or null if nothing is set.
     */
    private function resolveCase(PensionCase $case, array $statusMap): ?array
    {
        foreach ($this->typeColumn as $claimType => $column) {
            $raw = trim((string) $case->$column);

            if ($raw === '') {
                continue;
            }

            $statusId = $statusMap[$claimType][$this->normalise($raw)] ?? null;

            return [$claimType, $statusId, $raw];
        }

        return null;
    }

    /**
     * Build a lookup: claimType → normalisedName → statusId.
     * Normalisation strips extra whitespace and lowercases so minor
     * formatting differences in the legacy data still match.
     */
    private function buildStatusMap(): array
    {
        $map = [];

        $statuses = Status::whereIn('type', ['pension-bank', 'pension-fos', 'pension-fscs'])->get();

        foreach ($statuses as $status) {
            // type is 'pension-bank' etc.; strip the prefix to get 'bank'
            $claimType = str_replace('pension-', '', $status->type);
            $map[$claimType][$this->normalise($status->display_name)] = $status->id;
        }

        return $map;
    }

    private function normalise(string $value): string
    {
        // Lowercase, collapse whitespace, normalise dashes/hyphens to a plain hyphen
        $value = mb_strtolower($value);
        $value = preg_replace('/\s+/', ' ', $value);
        $value = preg_replace('/[\x{2013}\x{2014}]/u', '-', $value); // en-dash, em-dash → hyphen
        return trim($value);
    }
}
