<?php

namespace App\Console\Commands;

use App\Models\Area;
use App\Models\OrdenLavanderia;
use App\Models\OrderAreaPresence;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

/**
 * Herramienta de mantenimiento: filas en order_area_presences para órdenes legacy sin presencia TIBU.
 *
 * Uso típico:
 *   php artisan laundry:backfill-presence --dry-run
 *   php artisan laundry:backfill-presence --apply
 *
 * El mapeo current_step → código de área es heurístico (config/lavanderia.php). Validar en staging.
 */
class LaundryBackfillPresenceCommand extends Command
{
    protected $signature = 'laundry:backfill-presence
                            {--dry-run : Solo listar candidatos y conteos; no escribe en BD}
                            {--apply : Crear filas de presencia inferidas (requiere confirmación explícita en prod)}
                            {--limit=500 : Máximo de órdenes a procesar}';

    protected $description = 'Backfill de presencia por área para órdenes sin filas en order_area_presences (migración de datos).';

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

        if ($apply && $dryRun) {
            $this->error('Use solo --dry-run o solo --apply, no ambos.');

            return self::FAILURE;
        }

        if (! $dryRun && ! $apply) {
            $this->warn('Indique --dry-run (recomendado primero) o --apply.');
            $dryRun = true;
        }

        $map = config('lavanderia.backfill_step_to_area_code', []);

        $query = OrdenLavanderia::query()
            ->whereIn('estatus', [
                OrdenLavanderia::ESTATUS_PENDIENTE,
                OrdenLavanderia::ESTATUS_EN_PROCESO,
            ])
            ->whereDoesntHave('areaPresences')
            ->orderBy('id');

        $total = (clone $query)->count();
        $ordenes = (clone $query)->limit($limit)->get(['id', 'current_step', 'estatus']);

        $this->info("Candidatos (sin presencias, pendiente/en_proceso): {$total} (procesando hasta {$limit}).");

        if ($ordenes->isEmpty()) {
            $this->info('Nada que hacer.');

            return self::SUCCESS;
        }

        $created = 0;
        $skipped = 0;

        foreach ($ordenes as $orden) {
            $step = (string) $orden->current_step;
            $code = $map[$step] ?? null;

            if ($code === null) {
                ++$skipped;
                $this->line("  Orden #{$orden->id} step={$step} → sin mapeo; omitida.");

                continue;
            }

            $area = Area::query()->where('code', $code)->first();
            if ($area === null) {
                ++$skipped;
                $this->warn("  Orden #{$orden->id} → área code={$code} no existe; omitida.");

                continue;
            }

            if ($dryRun) {
                $this->line("  [dry-run] Orden #{$orden->id} → área {$code} (id {$area->id})");

                continue;
            }

            DB::transaction(function () use ($orden, $area, &$created): void {
                $row = OrderAreaPresence::query()->firstOrCreate(
                    [
                        'orden_lavanderia_id' => $orden->id,
                        'area_id' => $area->id,
                    ],
                    [
                        'status' => $orden->estatus === OrdenLavanderia::ESTATUS_EN_PROCESO
                            ? OrderAreaPresence::STATUS_IN_PROGRESS
                            : OrderAreaPresence::STATUS_PENDING,
                        'started_at' => null,
                        'completed_at' => null,
                    ]
                );
                if ($row->wasRecentlyCreated) {
                    ++$created;
                }
            });
        }

        if ($dryRun) {
            $this->info('Modo dry-run: no se escribió en la base de datos.');
        } else {
            $this->info("Filas creadas/aseguradas: {$created}. Omitidas: {$skipped}.");
        }

        return self::SUCCESS;
    }
}
