<?php

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

/**
 * One record of an operator settling a participant's account.
 *
 * A settlement is not one invoice and not one payment: it is the set of
 * corrections an admin decided a player's file needed, applied together. A
 * player who paid two months in cash that were never entered, was over-billed
 * for the month he joined halfway through, and bought a registration card that
 * nobody put through the till, is one settlement carrying four actions — not
 * four unrelated edits that nobody can later tie to the same decision.
 *
 * Why a table and not just the audit log: money moved on somebody's judgement,
 * and the question asked afterwards is always "who decided this, what did they
 * see, and what did it cost us". `actions` keeps each step and its result
 * (invoice and payment ids included), and the three amount columns make the
 * cost readable without parsing JSON — how much was collected, how much was
 * written off, how much was newly billed.
 *
 * Immutable by convention, like transactions and audit_logs: a settlement that
 * turns out to be wrong is corrected by a second settlement, never by editing
 * the first.
 */
return new class extends Migration
{
    public function up(): void
    {
        if (Schema::hasTable('settlements')) {
            return;
        }

        Schema::create('settlements', function (Blueprint $table) {
            $table->id();
            $table->uuid('uuid')->unique();
            $table->foreignId('academy_id')->constrained('academies')->cascadeOnDelete();
            $table->foreignId('branch_id')->nullable()->constrained('branches')->nullOnDelete();
            $table->foreignId('participant_id')->constrained('participants')->cascadeOnDelete();

            // Human-facing handle, printed on the summary the operator hands over.
            $table->string('reference');

            // Why the account needed settling. Required — a settlement with no
            // stated reason is indistinguishable from a mistake six months on.
            $table->text('reason');

            // Every action and what it produced, in the order applied.
            $table->json('actions');

            // The cost of the decision, split so it can be reported on directly.
            $table->bigInteger('collected_amount')->default(0);
            $table->bigInteger('waived_amount')->default(0);
            $table->bigInteger('billed_amount')->default(0);

            $table->foreignId('applied_by')->nullable()->constrained('users')->nullOnDelete();
            $table->timestamp('applied_at');
            $table->timestamps();

            // Tenant-scoped uniqueness, per the academy_id rule: two academies
            // may both hold SET-000001.
            $table->unique(['academy_id', 'reference'], 'settlements_reference_unique');
            $table->index(['academy_id', 'participant_id']);
            $table->index(['branch_id', 'applied_at']);
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('settlements');
    }
};
