<?php

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

/**
 * Otimizações de banco de dados para escalabilidade futura
 */
return new class extends Migration
{
    private function indexExists(string $table, string $indexName): bool
    {
        $result = DB::select("SHOW INDEX FROM {$table} WHERE Key_name = ?", [$indexName]);
        return count($result) > 0;
    }

    private function columnExists(string $table, string $column): bool
    {
        return Schema::hasColumn($table, $column);
    }

    public function up(): void
    {
        // ============================================================
        // 1. ÍNDICES COMPOSTOS PARA RELATÓRIOS (Dashboard)
        // ============================================================
        
        if (!$this->indexExists('transactions', 'idx_trans_dashboard_period')) {
            DB::statement('CREATE INDEX idx_trans_dashboard_period ON transactions (user_id, account_id, effective_date, type)');
        }

        if (!$this->indexExists('transactions', 'idx_trans_category_sum')) {
            DB::statement('CREATE INDEX idx_trans_category_sum ON transactions (user_id, category_id, effective_date, amount)');
        }

        if (!$this->indexExists('transactions', 'idx_trans_duplicate_check')) {
            DB::statement('CREATE INDEX idx_trans_duplicate_check ON transactions (user_id, account_id, effective_date, amount, description(100))');
        }

        // ============================================================
        // 2. ÍNDICES FULLTEXT PARA KEYWORDS (Auto-categorização)
        // ============================================================
        
        if (!$this->indexExists('category_keywords', 'ft_keyword')) {
            DB::statement('CREATE FULLTEXT INDEX ft_keyword ON category_keywords (keyword)');
        }

        if (!$this->indexExists('cost_center_keywords', 'ft_cc_keyword')) {
            DB::statement('CREATE FULLTEXT INDEX ft_cc_keyword ON cost_center_keywords (keyword)');
        }

        // ============================================================
        // 3. ÍNDICE FULLTEXT PARA BUSCA DE TEXTO (Transactions)
        // ============================================================
        
        if (!$this->indexExists('transactions', 'ft_trans_description')) {
            DB::statement('CREATE FULLTEXT INDEX ft_trans_description ON transactions (description)');
        }

        // ============================================================
        // 4. COLUNA DE PERÍODO PARA PARTICIONAMENTO FUTURO
        // ============================================================
        
        if (!$this->columnExists('transactions', 'period')) {
            DB::statement("ALTER TABLE transactions ADD COLUMN period CHAR(7) NULL COMMENT 'YYYY-MM for future partitioning' AFTER effective_date");
            
            // Preencher coluna period com dados existentes
            DB::statement("UPDATE transactions SET period = DATE_FORMAT(effective_date, '%Y-%m') WHERE period IS NULL AND effective_date IS NOT NULL");
            
            // Índice para queries por período
            DB::statement('CREATE INDEX idx_trans_period ON transactions (user_id, period)');
        }

        // ============================================================
        // 5. TRIGGERS PARA MANTER PERIOD ATUALIZADO
        // ============================================================
        
        DB::unprepared('DROP TRIGGER IF EXISTS tr_transactions_period_insert');
        DB::unprepared("
            CREATE TRIGGER tr_transactions_period_insert
            BEFORE INSERT ON transactions
            FOR EACH ROW
            BEGIN
                IF NEW.period IS NULL AND NEW.effective_date IS NOT NULL THEN
                    SET NEW.period = DATE_FORMAT(NEW.effective_date, '%Y-%m');
                END IF;
            END
        ");

        DB::unprepared('DROP TRIGGER IF EXISTS tr_transactions_period_update');
        DB::unprepared("
            CREATE TRIGGER tr_transactions_period_update
            BEFORE UPDATE ON transactions
            FOR EACH ROW
            BEGIN
                IF NEW.effective_date != OLD.effective_date OR NEW.period IS NULL THEN
                    SET NEW.period = DATE_FORMAT(NEW.effective_date, '%Y-%m');
                END IF;
            END
        ");

        // ============================================================
        // 6. ÍNDICE PARA LIABILITY (Parcelas a vencer)
        // ============================================================
        
        if (!$this->indexExists('liability_installments', 'idx_liab_pending_due')) {
            DB::statement('CREATE INDEX idx_liab_pending_due ON liability_installments (status, due_date)');
        }

        // ============================================================
        // 7. OTIMIZAÇÃO DE COLUNAS (ENUM - menor footprint)
        // ============================================================
        
        DB::statement("ALTER TABLE transactions MODIFY COLUMN status ENUM('effective', 'pending', 'scheduled', 'cancelled', 'completed') NOT NULL DEFAULT 'effective'");
        DB::statement("ALTER TABLE transactions MODIFY COLUMN type ENUM('credit', 'debit', 'income', 'expense', 'transfer') NOT NULL");

        // ============================================================
        // 8. ATUALIZAR ESTATÍSTICAS PARA OTIMIZADOR
        // ============================================================
        
        DB::statement('ANALYZE TABLE transactions');
        DB::statement('ANALYZE TABLE categories');
        DB::statement('ANALYZE TABLE category_keywords');
        DB::statement('ANALYZE TABLE accounts');
    }

    public function down(): void
    {
        // Remover triggers
        DB::unprepared('DROP TRIGGER IF EXISTS tr_transactions_period_insert');
        DB::unprepared('DROP TRIGGER IF EXISTS tr_transactions_period_update');

        // Remover índices de transactions
        if ($this->indexExists('transactions', 'idx_trans_dashboard_period')) {
            DB::statement('DROP INDEX idx_trans_dashboard_period ON transactions');
        }
        if ($this->indexExists('transactions', 'idx_trans_category_sum')) {
            DB::statement('DROP INDEX idx_trans_category_sum ON transactions');
        }
        if ($this->indexExists('transactions', 'idx_trans_duplicate_check')) {
            DB::statement('DROP INDEX idx_trans_duplicate_check ON transactions');
        }
        if ($this->indexExists('transactions', 'ft_trans_description')) {
            DB::statement('DROP INDEX ft_trans_description ON transactions');
        }
        if ($this->indexExists('transactions', 'idx_trans_period')) {
            DB::statement('DROP INDEX idx_trans_period ON transactions');
        }

        // Remover coluna period
        if ($this->columnExists('transactions', 'period')) {
            DB::statement('ALTER TABLE transactions DROP COLUMN period');
        }

        // Remover full-text de keywords
        if ($this->indexExists('category_keywords', 'ft_keyword')) {
            DB::statement('DROP INDEX ft_keyword ON category_keywords');
        }
        if ($this->indexExists('cost_center_keywords', 'ft_cc_keyword')) {
            DB::statement('DROP INDEX ft_cc_keyword ON cost_center_keywords');
        }

        // Remover índice de liability
        if ($this->indexExists('liability_installments', 'idx_liab_pending_due')) {
            DB::statement('DROP INDEX idx_liab_pending_due ON liability_installments');
        }

        // Reverter ENUM para VARCHAR
        DB::statement("ALTER TABLE transactions MODIFY COLUMN status VARCHAR(255) NOT NULL DEFAULT 'effective'");
        DB::statement("ALTER TABLE transactions MODIFY COLUMN type VARCHAR(255) NOT NULL");
    }
};
