<?php

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

/**
 * Six CHECK constraints carry a payment-method vocabulary and they already
 * disagree with each other: `payslips` allows 'instapay' and nothing else
 * does, and `pos_transactions` / `pos_split_payments` have no 'bank_transfer'
 * at all.
 *
 * All five that lack it get 'instapay' in one migration, the till included.
 * Reception will take an InstaPay transfer within a month of launch, and the
 * failure mode of leaving the POS out is a Postgres 23514 at the till, in
 * front of a customer, with no way for the cashier to complete the sale.
 *
 * Widening a CHECK is safe against a populated table: every row that passed
 * the old list passes the superset. DROP IF EXISTS + ADD run inside the
 * migration's transaction, so a failure leaves the original in place.
 */
return new class extends Migration
{
    private const OFFICE = ['cash', 'card', 'bank_transfer', 'instapay', 'wallet', 'online', 'cheque', 'other'];

    /** The till also gains bank_transfer, which it has always been missing. */
    private const TILL = ['cash', 'card', 'bank_transfer', 'instapay', 'wallet', 'split'];

    private const TARGETS = [
        ['payments', 'method', 'payments_method_check', self::OFFICE],
        ['expenses', 'payment_method', 'expenses_payment_method_check', self::OFFICE],
        ['facility_rent_payments', 'payment_method', 'facility_rent_payments_payment_method_check', self::OFFICE],
        ['pos_transactions', 'payment_method', 'pos_transactions_payment_method_check', self::TILL],
        ['pos_split_payments', 'payment_method', 'pos_split_payments_payment_method_check', self::TILL],
    ];

    public function up(): void
    {
        if (DB::getDriverName() !== 'pgsql') {
            return;
        }

        foreach (self::TARGETS as [$table, $column, $constraint, $values]) {
            if (! Schema::hasTable($table) || ! Schema::hasColumn($table, $column)) {
                continue;
            }

            $list = implode(', ', array_map(fn ($v) => "'{$v}'", $values));

            DB::statement("ALTER TABLE {$table} DROP CONSTRAINT IF EXISTS {$constraint}");
            DB::statement("ALTER TABLE {$table} ADD CONSTRAINT {$constraint} CHECK ({$column} IN ({$list}))");
        }
    }

    public function down(): void
    {
        // Deliberately empty. Narrowing a CHECK would fail on any row already
        // recorded as instapay, and the failure would land mid-boot.
    }
};
