<?php

namespace App\Database\Migrations;

use CodeIgniter\Database\Migration;

class CreateSchoolYears extends Migration
{
    public function up(): void
    {
        if (! $this->db->tableExists('school_years')) {
            $this->forge->addField([
                'id' => [
                    'type' => 'INT',
                    'constraint' => 11,
                    'unsigned' => true,
                    'auto_increment' => true,
                ],
                'name' => [
                    'type' => 'VARCHAR',
                    'constraint' => 9,
                    'null' => false,
                ],
                'status' => [
                    'type' => 'VARCHAR',
                    'constraint' => 20,
                    'null' => false,
                    'default' => 'draft',
                ],
                'starts_on' => [
                    'type' => 'DATE',
                    'null' => true,
                ],
                'ends_on' => [
                    'type' => 'DATE',
                    'null' => true,
                ],
                'description' => [
                    'type' => 'TEXT',
                    'null' => true,
                ],
                'registration_starts_on' => [
                    'type' => 'DATE',
                    'null' => true,
                ],
                'registration_ends_on' => [
                    'type' => 'DATE',
                    'null' => true,
                ],
                'previous_school_year_id' => [
                    'type' => 'INT',
                    'constraint' => 11,
                    'unsigned' => true,
                    'null' => true,
                ],
                'next_school_year_id' => [
                    'type' => 'INT',
                    'constraint' => 11,
                    'unsigned' => true,
                    'null' => true,
                ],
                'activated_at' => [
                    'type' => 'DATETIME',
                    'null' => true,
                ],
                'closing_started_at' => [
                    'type' => 'DATETIME',
                    'null' => true,
                ],
                'closed_at' => [
                    'type' => 'DATETIME',
                    'null' => true,
                ],
                'archived_at' => [
                    'type' => 'DATETIME',
                    'null' => true,
                ],
                'created_by' => [
                    'type' => 'INT',
                    'constraint' => 11,
                    'unsigned' => true,
                    'null' => true,
                ],
                'updated_by' => [
                    'type' => 'INT',
                    'constraint' => 11,
                    'unsigned' => true,
                    'null' => true,
                ],
                'created_at' => [
                    'type' => 'DATETIME',
                    'null' => true,
                ],
                'updated_at' => [
                    'type' => 'DATETIME',
                    'null' => true,
                ],
            ]);

            $this->forge->addKey('id', true);
            $this->forge->addKey('name', false, true);
            $this->forge->addKey('status');
            $this->forge->createTable('school_years');
        } else {
            $this->ensureSchoolYearColumns();
        }

        $this->createClosingTables();

        $configuredYear = $this->configuredSchoolYear();

        if ($configuredYear !== null && $this->isValidYearName($configuredYear)) {
            $existing = $this->db->table('school_years')
                ->where('name', $configuredYear)
                ->get()
                ->getRowArray();

            if ($existing === null) {
                $this->db->table('school_years')->insert([
                    'name' => $configuredYear,
                    'status' => 'active',
                    'activated_at' => date('Y-m-d H:i:s'),
                    'created_at' => date('Y-m-d H:i:s'),
                    'updated_at' => date('Y-m-d H:i:s'),
                ]);
            }
        }
    }

    public function down(): void
    {
        $this->forge->dropTable('school_year_transition_logs', true);
        $this->forge->dropTable('school_year_closing_items', true);
        $this->forge->dropTable('school_year_closing_batches', true);
        $this->forge->dropTable('school_years', true);
    }

    private function ensureSchoolYearColumns(): void
    {
        $fields = $this->db->getFieldNames('school_years');
        $add = [];

        $definitions = [
            'description' => ['type' => 'TEXT', 'null' => true],
            'registration_starts_on' => ['type' => 'DATE', 'null' => true],
            'registration_ends_on' => ['type' => 'DATE', 'null' => true],
            'previous_school_year_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
            'next_school_year_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
            'activated_at' => ['type' => 'DATETIME', 'null' => true],
            'closing_started_at' => ['type' => 'DATETIME', 'null' => true],
            'closed_at' => ['type' => 'DATETIME', 'null' => true],
            'archived_at' => ['type' => 'DATETIME', 'null' => true],
            'created_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
            'updated_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
        ];

        foreach ($definitions as $field => $definition) {
            if (! in_array($field, $fields, true)) {
                $add[$field] = $definition;
            }
        }

        if ($add !== []) {
            $this->forge->addColumn('school_years', $add);
        }
    }

    private function createClosingTables(): void
    {
        if (! $this->db->tableExists('school_year_closing_batches')) {
            $this->forge->addField([
                'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
                'source_school_year_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
                'target_school_year_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
                'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'null' => false, 'default' => 'preview'],
                'preview_hash' => ['type' => 'CHAR', 'constraint' => 64, 'null' => true],
                'total_families' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => false, 'default' => 0],
                'total_positive_balance' => ['type' => 'DECIMAL', 'constraint' => '12,2', 'null' => false, 'default' => '0.00'],
                'total_credit_balance' => ['type' => 'DECIMAL', 'constraint' => '12,2', 'null' => false, 'default' => '0.00'],
                'started_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
                'completed_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
                'started_at' => ['type' => 'DATETIME', 'null' => true],
                'completed_at' => ['type' => 'DATETIME', 'null' => true],
                'failed_at' => ['type' => 'DATETIME', 'null' => true],
                'failure_message' => ['type' => 'TEXT', 'null' => true],
                'created_at' => ['type' => 'DATETIME', 'null' => true],
                'updated_at' => ['type' => 'DATETIME', 'null' => true],
            ]);
            $this->forge->addKey('id', true);
            $this->forge->addKey(['source_school_year_id', 'status']);
            $this->forge->createTable('school_year_closing_batches');
        }

        if (! $this->db->tableExists('school_year_closing_items')) {
            $this->forge->addField([
                'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
                'closing_batch_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
                'family_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
                'source_balance' => ['type' => 'DECIMAL', 'constraint' => '12,2', 'null' => false, 'default' => '0.00'],
                'credit_amount' => ['type' => 'DECIMAL', 'constraint' => '12,2', 'null' => false, 'default' => '0.00'],
                'adjustment_amount' => ['type' => 'DECIMAL', 'constraint' => '12,2', 'null' => false, 'default' => '0.00'],
                'carry_forward_amount' => ['type' => 'DECIMAL', 'constraint' => '12,2', 'null' => false, 'default' => '0.00'],
                'target_invoice_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
                'target_adjustment_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
                'status' => ['type' => 'VARCHAR', 'constraint' => 30, 'null' => false, 'default' => 'pending'],
                'error_message' => ['type' => 'TEXT', 'null' => true],
                'created_at' => ['type' => 'DATETIME', 'null' => true],
                'updated_at' => ['type' => 'DATETIME', 'null' => true],
            ]);
            $this->forge->addKey('id', true);
            $this->forge->addKey(['closing_batch_id', 'family_id'], false, true);
            $this->forge->createTable('school_year_closing_items');
        }

        if (! $this->db->tableExists('school_year_transition_logs')) {
            $this->forge->addField([
                'id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
                'school_year_id' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true],
                'from_status' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
                'to_status' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
                'action' => ['type' => 'VARCHAR', 'constraint' => 80, 'null' => false],
                'performed_by' => ['type' => 'INT', 'constraint' => 11, 'unsigned' => true, 'null' => true],
                'metadata_json' => ['type' => 'TEXT', 'null' => true],
                'created_at' => ['type' => 'DATETIME', 'null' => false],
            ]);
            $this->forge->addKey('id', true);
            $this->forge->addKey(['school_year_id', 'created_at']);
            $this->forge->createTable('school_year_transition_logs');
        }
    }

    private function configuredSchoolYear(): ?string
    {
        if (! $this->db->tableExists('configuration')) {
            return null;
        }

        $row = $this->db->table('configuration')
            ->select('config_value')
            ->where('config_key', 'school_year')
            ->orderBy('id', 'DESC')
            ->get(1)
            ->getRowArray();

        $value = trim((string) ($row['config_value'] ?? ''));

        return $value !== '' ? $value : null;
    }

    private function isValidYearName(string $value): bool
    {
        if (! preg_match('/^(\d{4})-(\d{4})$/', $value, $matches)) {
            return false;
        }

        return (int) $matches[2] === (int) $matches[1] + 1;
    }
}
