<?php

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

return new class extends Migration
{
    public function up(): void
    {
        if (!Schema::hasTable('school_years')) {
            Schema::create('school_years', function (Blueprint $table) {
                $table->id();
                $table->string('name', 50)->unique();
                $table->date('start_date');
                $table->date('end_date');
                $table->string('status', 20)->default('draft')->index();
                $table->boolean('is_current')->default(false)->index();
                $table->timestamp('closed_at')->nullable();
                $table->unsignedBigInteger('closed_by')->nullable()->index();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('parent_accounts')) {
            Schema::create('parent_accounts', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('parent_id')->index();
                $table->string('school_year', 50)->index();
                $table->decimal('opening_balance', 12, 2)->default(0);
                $table->decimal('current_balance', 12, 2)->default(0);
                $table->timestamps();
                $table->unique(['parent_id', 'school_year'], 'parent_accounts_parent_year_unique');
            });
        }

        if (!Schema::hasTable('parent_balance_transfers')) {
            Schema::create('parent_balance_transfers', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('parent_id')->index();
                $table->string('from_school_year', 50)->index();
                $table->string('to_school_year', 50)->index();
                $table->decimal('amount', 12, 2)->default(0);
                $table->string('status', 30)->default('pending')->index();
                $table->json('source_summary_json')->nullable();
                $table->unsignedBigInteger('new_invoice_id')->nullable()->index();
                $table->unsignedBigInteger('created_by')->nullable()->index();
                $table->timestamps();
                $table->unique(['parent_id', 'from_school_year', 'to_school_year'], 'parent_balance_transfers_parent_year_unique');
            });
        }

        if (!Schema::hasTable('audit_logs')) {
            Schema::create('audit_logs', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('user_id')->nullable()->index();
                $table->string('action', 100)->index();
                $table->string('table_name', 100)->nullable()->index();
                $table->unsignedBigInteger('record_id')->nullable()->index();
                $table->json('old_value')->nullable();
                $table->json('new_value')->nullable();
                $table->json('metadata')->nullable();
                $table->timestamp('created_at')->nullable();
            });
        }

        if (Schema::hasTable('invoices') && !Schema::hasColumn('invoices', 'balance_transfer_id')) {
            Schema::table('invoices', function (Blueprint $table) {
                $table->unsignedBigInteger('balance_transfer_id')->nullable()->index()->after('semester');
            });
        }

        $this->seedCurrentSchoolYear();
    }

    public function down(): void
    {
        if (Schema::hasTable('invoices') && Schema::hasColumn('invoices', 'balance_transfer_id')) {
            Schema::table('invoices', function (Blueprint $table) {
                $table->dropColumn('balance_transfer_id');
            });
        }

        Schema::dropIfExists('audit_logs');
        Schema::dropIfExists('parent_balance_transfers');
        Schema::dropIfExists('parent_accounts');
        Schema::dropIfExists('school_years');
    }

    private function seedCurrentSchoolYear(): void
    {
        if (!Schema::hasTable('configuration') || !Schema::hasTable('school_years')) {
            return;
        }

        $current = DB::table('configuration')
            ->where('config_key', 'school_year')
            ->orderByDesc('id')
            ->value('config_value');

        $current = is_string($current) ? trim($current) : '';
        if ($current === '') {
            return;
        }

        $exists = DB::table('school_years')->where('name', $current)->exists();
        if ($exists) {
            DB::table('school_years')->where('name', $current)->update([
                'status' => 'active',
                'is_current' => true,
                'updated_at' => now(),
            ]);
            return;
        }

        [$startDate, $endDate] = $this->inferDates($current);

        DB::table('school_years')->insert([
            'name' => $current,
            'start_date' => $startDate,
            'end_date' => $endDate,
            'status' => 'active',
            'is_current' => true,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function inferDates(string $schoolYear): array
    {
        if (preg_match('/^(\\d{4})-(\\d{4})$/', $schoolYear, $matches) === 1) {
            return [
                sprintf('%s-09-01', $matches[1]),
                sprintf('%s-06-30', $matches[2]),
            ];
        }

        $year = (int) date('Y');

        return [
            sprintf('%d-09-01', $year),
            sprintf('%d-06-30', $year + 1),
        ];
    }
};
