<?php

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

/**
 * Configurable applicant workflow (§8).
 *
 * The lifecycle is data, not code: an agency defines its own pipelines, the
 * stages within them, which transitions are legal, and what must be true before
 * each stage can be entered.
 */
return new class extends Migration
{
    public function up(): void
    {
        Schema::create('pipelines', function (Blueprint $table) {
            $table->id();
            $table->uuid('uuid')->unique();
            $table->foreignId('company_id')->constrained()->cascadeOnUpdate()->restrictOnDelete();
            $table->string('code', 40);
            $table->string('name');
            $table->text('description')->nullable();
            // Optional narrowing: a pipeline may serve one destination country.
            $table->string('destination_country', 2)->nullable();
            $table->boolean('is_default')->default(false);
            $table->boolean('is_active')->default(true);
            $table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
            $table->timestamps();
            $table->softDeletes();

            $table->unique(['company_id', 'code']);
            $table->index(['company_id', 'is_active']);
        });

        Schema::create('pipeline_stages', function (Blueprint $table) {
            $table->id();
            $table->uuid('uuid')->unique();
            $table->foreignId('pipeline_id')->constrained()->cascadeOnDelete();
            $table->string('code', 40);
            $table->string('name');
            $table->unsignedSmallInteger('sequence');

            // What the applicant is shown in their portal (§8) — never the
            // internal stage name, which may be blunt.
            $table->string('applicant_visible_label')->nullable();
            $table->text('applicant_visible_description')->nullable();
            $table->boolean('is_visible_to_applicant')->default(true);

            $table->string('color', 20)->nullable();
            $table->string('icon', 40)->nullable();

            $table->boolean('is_initial')->default(false);
            $table->boolean('is_terminal')->default(false);
            // An exception stage (on hold, rejected) sits outside the happy path.
            $table->boolean('is_exception')->default(false);
            $table->boolean('requires_approval')->default(false);

            // Target working days in this stage before it is flagged (§87).
            $table->unsignedSmallInteger('sla_days')->nullable();

            // Conditions that must hold to ENTER this stage. Each entry is
            // {"type": "...", "params": {...}} resolved by the requirement registry.
            $table->json('entry_requirements')->nullable();
            // Fired after a successful move into this stage.
            $table->json('automatic_actions')->nullable();

            $table->boolean('is_active')->default(true);
            $table->timestamps();
            $table->softDeletes();

            $table->unique(['pipeline_id', 'code']);
            $table->index(['pipeline_id', 'sequence']);
        });

        // Explicit allow-list of moves. Absence of a row means the move is illegal.
        Schema::create('pipeline_transitions', function (Blueprint $table) {
            $table->id();
            $table->foreignId('pipeline_id')->constrained()->cascadeOnDelete();
            $table->foreignId('from_stage_id')->nullable()->constrained('pipeline_stages')->cascadeOnDelete();
            $table->foreignId('to_stage_id')->constrained('pipeline_stages')->cascadeOnDelete();
            // Role names permitted to make this move; null means any user holding
            // the applicant.change_stage permission.
            $table->json('allowed_roles')->nullable();
            $table->boolean('requires_reason')->default(false);
            $table->boolean('is_active')->default(true);
            $table->timestamps();

            $table->unique(['pipeline_id', 'from_stage_id', 'to_stage_id']);
        });

        Schema::create('applicant_stage_histories', function (Blueprint $table) {
            $table->id();
            $table->foreignId('applicant_id')->constrained()->cascadeOnDelete();
            $table->foreignId('pipeline_id')->nullable()->constrained()->nullOnDelete();
            $table->foreignId('from_stage_id')->nullable()->constrained('pipeline_stages')->nullOnDelete();
            $table->foreignId('to_stage_id')->constrained('pipeline_stages')->cascadeOnDelete();
            $table->foreignId('changed_by')->nullable()->constrained('users')->nullOnDelete();
            $table->timestamp('changed_at');
            $table->text('reason')->nullable();
            $table->text('notes')->nullable();
            // Records an authorized bypass of unmet entry requirements (§8).
            $table->boolean('was_overridden')->default(false);
            $table->json('unmet_requirements')->nullable();
            $table->json('metadata')->nullable();
            $table->timestamps();

            $table->index(['applicant_id', 'changed_at']);
        });

        Schema::table('applicants', function (Blueprint $table) {
            $table->foreignId('pipeline_id')->nullable()->after('job_demand_id')->constrained()->nullOnDelete();
            $table->foreignId('current_stage_id')->nullable()->after('pipeline_id')->constrained('pipeline_stages')->nullOnDelete();
            $table->timestamp('stage_entered_at')->nullable()->after('current_stage_id');

            $table->index(['pipeline_id', 'current_stage_id']);
        });
    }

    public function down(): void
    {
        Schema::table('applicants', function (Blueprint $table) {
            $table->dropConstrainedForeignId('current_stage_id');
            $table->dropConstrainedForeignId('pipeline_id');
            $table->dropColumn('stage_entered_at');
        });

        Schema::dropIfExists('applicant_stage_histories');
        Schema::dropIfExists('pipeline_transitions');
        Schema::dropIfExists('pipeline_stages');
        Schema::dropIfExists('pipelines');
    }
};
