<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

class UpdateVoterPelaburanFromJson extends Command
{
    protected $signature = 'voter:update-pelaburan-from-json
                            {--file=database/seeds/inject/list-pelabur.json : Relative path from project root}
                            {--election_id= : Override election_id (default: latest in voter table)}
                            {--dry-run : Show what would change without updating}';

    protected $description = 'Update voter pelaburan (dividen) from list-pelabur.json for latest election only';

    public function handle()
    {
        $fileOpt = (string) $this->option('file');
        $filePath = $this->resolvePath($fileOpt);

        if (!is_file($filePath)) {
            $this->error("❌ JSON file not found: {$filePath}");
            return 1;
        }

        $electionId = $this->option('election_id');
        $electionId = $electionId !== null && $electionId !== '' ? (int) $electionId : (int) DB::table('voter')->max('election_id');

        if ($electionId <= 0) {
            $this->error("❌ Cannot determine latest election_id (got {$electionId}).");
            return 1;
        }

        $json = file_get_contents($filePath);
        $rows = json_decode($json, true);

        if (!is_array($rows)) {
            $this->error("❌ Invalid JSON: expected array of rows.");
            return 1;
        }

        $map = [];
        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }

            $noAnggota = isset($row['no_anggota']) ? trim((string) $row['no_anggota']) : '';
            if ($noAnggota === '') {
                continue;
            }

            $pelaburanRaw = $row['pelaburan'] ?? 0;
            $map[$noAnggota] = $this->cleanNumber($pelaburanRaw);
        }

        if (count($map) === 0) {
            $this->error("❌ No usable rows found in JSON (missing no_anggota?).");
            return 1;
        }

        $dryRun = (bool) $this->option('dry-run');

        $this->info("Target election_id: {$electionId}");
        $this->info("JSON members loaded: " . count($map));
        $this->info($dryRun ? "Mode: DRY RUN (no DB updates)" : "Mode: UPDATE");

        $totalInElection = (int) DB::table('voter')->where('election_id', $electionId)->count();
        $this->info("Voters in election: {$totalInElection}");

        $updated = 0;
        $matched = 0;
        $missingInJson = 0;
        $unchanged = 0;

        $bar = $this->output->createProgressBar(max(1, $totalInElection));
        $bar->start();

        DB::table('voter')
            ->select(['id', 'no_anggota', 'pelaburan'])
            ->where('election_id', $electionId)
            ->orderBy('id')
            ->chunkById(500, function ($chunk) use ($map, $dryRun, &$updated, &$matched, &$missingInJson, &$unchanged, $bar) {
                foreach ($chunk as $voter) {
                    $noAnggota = $voter->no_anggota !== null ? trim((string) $voter->no_anggota) : '';

                    if ($noAnggota === '' || !array_key_exists($noAnggota, $map)) {
                        $missingInJson++;
                        $bar->advance();
                        continue;
                    }

                    $matched++;

                    $newPelaburan = $map[$noAnggota];
                    $oldPelaburan = $voter->pelaburan !== null ? (float) $voter->pelaburan : 0.0;

                    if (abs($oldPelaburan - $newPelaburan) < 0.00001) {
                        $unchanged++;
                        $bar->advance();
                        continue;
                    }

                    if (!$dryRun) {
                        DB::table('voter')
                            ->where('id', $voter->id)
                            ->update([
                                'pelaburan' => $newPelaburan,
                                'updated_at' => now(),
                            ]);
                    }

                    $updated++;
                    $bar->advance();
                }
            }, 'id');

        $bar->finish();
        $this->line('');

        $this->info("✅ Matched in JSON: {$matched}");
        $this->info("✅ Updated: {$updated}" . ($dryRun ? " (would update)" : ""));
        $this->info("✅ Unchanged: {$unchanged}");
        $this->info("⚠️ Missing in JSON: {$missingInJson}");

        return 0;
    }

    private function resolvePath(string $path): string
    {
        // absolute path
        if (strpos($path, DIRECTORY_SEPARATOR) === 0) {
            return $path;
        }

        return base_path($path);
    }

    private function cleanNumber($value): float
    {
        if ($value === null) {
            return 0.0;
        }

        $value = (string) $value;
        $value = str_replace(['RM', ',', ' '], '', $value);

        if (preg_match('/^\((.*)\)$/', $value, $matches)) {
            $value = $matches[1];
        }

        $value = preg_replace('/[^0-9\.\-]/', '', $value);

        return is_numeric($value) ? (float) $value : 0.0;
    }
}

