<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

/**
 * Cobros capturados en campo que la cola offline no pudo aplicar con seguridad
 * (PWA-001). Viven FUERA de `payments` a propósito: todo total, reporte y KPI
 * suma `payments`, y un cobro retenido no debe contar hasta que alguien lo apruebe.
 */
return new class extends Migration
{
    public function up(): void
    {
        Schema::create('held_payments', function (Blueprint $table) {
            $table->id();
            $table->foreignId('company_id')->constrained()->cascadeOnDelete();
            $table->uuid('idempotency_key');
            // Solo se enlaza si el crédito es de la misma empresa; el id crudo queda en `payload`.
            $table->foreignId('credit_id')->nullable()->constrained()->nullOnDelete();
            // Si se borra el usuario, la referencia queda en null (igual que en el
            // resto de la app: credify:reset-demo y el borrado desde /admin lo
            // necesitan). El id del capturador sobrevive en `payload` si el
            // teléfono lo mandó; quién subió y quién resolvió se pierden.
            $table->foreignId('captured_by_user_id')->nullable()->constrained('users')->nullOnDelete();
            $table->foreignId('synced_by_user_id')->nullable()->constrained('users')->nullOnDelete();
            // Nulos solo si llegaron ilegibles (motivo `invalid`).
            $table->decimal('amount', 12, 2)->nullable();
            $table->string('payment_method', 20)->nullable();
            $table->date('payment_date')->nullable();
            $table->dateTime('offline_created_at')->nullable();
            $table->string('device_id')->nullable();
            $table->decimal('latitude', 10, 7)->nullable();
            $table->decimal('longitude', 10, 7)->nullable();
            $table->string('reason', 30);
            $table->string('reason_detail')->nullable();
            $table->json('payload');
            $table->string('status', 20)->default('pending');
            // Si se borra el usuario, la referencia queda en null (igual que en
            // el resto de la app); este id nunca está en `payload`.
            $table->foreignId('resolved_by_user_id')->nullable()->constrained('users')->nullOnDelete();
            $table->timestamp('resolved_at')->nullable();
            $table->text('resolution_notes')->nullable();
            $table->foreignId('payment_id')->nullable()->constrained()->nullOnDelete();
            $table->timestamps();

            $table->unique(['company_id', 'idempotency_key']);
            $table->index(['company_id', 'status']);
            // Un cobro retenido produce a lo sumo un pago; MySQL permite varios NULL.
            $table->unique('payment_id');
        });
    }

    /**
     * Un retenido es la única copia de un cobro que el cliente sí entregó (el
     * teléfono ya lo soltó): con filas, revertir se niega en vez de borrarlas.
     */
    public function down(): void
    {
        if (Schema::hasTable('held_payments') && DB::table('held_payments')->exists()) {
            throw new RuntimeException(
                'La tabla held_payments contiene cobros retenidos; son la única copia de dinero cobrado. '
                .'Exporta y resuélvelos antes de revertir.'
            );
        }

        Schema::dropIfExists('held_payments');
    }
};
