<?php

declare(strict_types=1);

namespace App\Console\Commands;

use App\Jobs\Supplier\DeleteSupplierProjectJob;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

/**
 * One-time migration: clean up orphan supplier_projects rows created by the
 * now-removed buildUniqueKey($p, $platform) divergence for SMS+keyword projects.
 *
 * Before R-17 unification (Stage 4 §4.4.1) SMS+keyword projects had two diverging
 * supplier_projects keys per group:
 *   B2: unique_key = sender+keyword
 *   B3: unique_key = sender (without keyword) — ORPHAN after unification
 *
 * This command finds orphan B3 rows (sms, no '+' in unique_key, owning project has
 * sms_keyword) and either UPDATEs them to sender+keyword (no sibling) or marks them
 * for deletion via DeleteSupplierProjectJob (sibling at sender+keyword already exists).
 *
 * Usage:
 *   php artisan supplier:rekey-orphans --dry-run   # preview
 *   php artisan supplier:rekey-orphans             # apply
 *
 * Spec §4.4.1.
 */
final class SupplierRekeyOrphansCommand extends Command
{
    protected $signature = 'supplier:rekey-orphans {--dry-run : Preview without modifying anything}';

    protected $description = 'One-time R-17 cleanup of orphan SMS supplier_projects keyed under sender alone';

    public function handle(): int
    {
        $dryRun = (bool) $this->option('dry-run');

        // Find candidate orphans: sms supplier_projects whose unique_key has no '+'
        // and whose tenant has an SMS project with sms_keyword set matching this sender.
        $orphans = DB::connection('pgsql_supplier')
            ->table('supplier_projects as sp')
            ->join('project_supplier_links as psl', 'psl.supplier_project_id', '=', 'sp.id')
            ->join('projects as p', 'p.id', '=', 'psl.project_id')
            ->where('sp.signal_type', 'sms')
            ->where('sp.unique_key', 'NOT LIKE', '%+%')
            ->whereNotNull('p.sms_keyword')
            ->where('p.sms_keyword', '!=', '')
            ->select([
                'sp.id as sp_id',
                'sp.unique_key as sender',
                'sp.platform',
                'p.tenant_id',
                'p.sms_keyword as keyword',
            ])
            ->get();

        if ($orphans->isEmpty()) {
            $this->info('No orphan SMS supplier_projects found. Nothing to migrate.');

            return self::SUCCESS;
        }

        $this->info(sprintf('Found %d orphan SMS supplier_projects row(s).', $orphans->count()));

        $updated = 0;
        $dispatched = 0;
        $toDelete = [];

        foreach ($orphans as $o) {
            $sender = (string) $o->sender;
            $keyword = (string) $o->keyword;
            $newKey = $sender.'+'.$keyword;

            // Sibling check: another supplier_project for same tenant/keyword combo already
            // exists at the unified key? Look across pivot to the same tenant scope.
            $siblingExists = DB::connection('pgsql_supplier')
                ->table('supplier_projects as sp2')
                ->join('project_supplier_links as psl2', 'psl2.supplier_project_id', '=', 'sp2.id')
                ->join('projects as p2', 'p2.id', '=', 'psl2.project_id')
                ->where('sp2.signal_type', 'sms')
                ->where('sp2.unique_key', $newKey)
                ->where('p2.tenant_id', $o->tenant_id)
                ->where('sp2.id', '!=', $o->sp_id)
                ->exists();

            if ($siblingExists) {
                $toDelete[] = (int) $o->sp_id;
                $this->line(sprintf(
                    '  orphan #%d (%s sender=%s) → DELETE (sibling at %s exists for tenant %d)',
                    $o->sp_id, $o->platform, $sender, $newKey, $o->tenant_id
                ));

                continue;
            }

            $this->line(sprintf(
                '  orphan #%d (%s sender=%s) → UPDATE unique_key=%s',
                $o->sp_id, $o->platform, $sender, $newKey
            ));

            if (! $dryRun) {
                DB::connection('pgsql_supplier')
                    ->table('supplier_projects')
                    ->where('id', $o->sp_id)
                    ->update(['unique_key' => $newKey, 'updated_at' => now()]);
                $updated++;
            }
        }

        if (! $dryRun && $toDelete !== []) {
            DeleteSupplierProjectJob::dispatch($toDelete);
            $dispatched = count($toDelete);
        }

        if ($dryRun) {
            $this->warn('--dry-run: no changes made.');
        } else {
            $this->info(sprintf(
                'Migration complete: %d row(s) updated, %d row(s) queued for deletion.',
                $updated, $dispatched
            ));
        }

        return self::SUCCESS;
    }
}
