<?php
declare(strict_types=1);

use App\Core\Database;

/**
 * Phase 32: Fix issues from Phase 31 deployment.
 *
 * Phase 31 used DROP CONSTRAINT (not supported for CHECK constraints in
 * this MySQL version), so 4 column renames were silently blocked.
 * Additionally, sections 21-25 of Phase 31 were not present in the
 * deployed code, so those changes need to be applied here.
 *
 * This migration is fully idempotent — safe to run on any DB state.
 */
return function (Database $db): void {

    $hasColumn = function (string $table, string $column) use ($db): bool {
        $row = $db->selectOne(
            "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?",
            [$table, $column]
        );
        return $row !== null;
    };

    $safeAlter = function (string $sql) use ($db): void {
        try {
            $db->raw($sql);
        } catch (\Throwable $e) {
            echo "      ⚠ " . $e->getMessage() . "\n";
        }
    };

    $findFkName = function (string $table, string $column) use ($db): ?string {
        $row = $db->selectOne(
            "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
             WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?
             AND REFERENCED_TABLE_NAME IS NOT NULL
             LIMIT 1",
            [$table, $column]
        );
        return $row ? $row['CONSTRAINT_NAME'] : null;
    };

    /**
     * Find FK constraint pointing a column to a SPECIFIC referenced table.
     * Used to find and drop orphaned FKs pointing to wrong table.
     */
    $findFkToTable = function (string $table, string $column, string $referencedTable) use ($db): ?string {
        $row = $db->selectOne(
            "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
             WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?
             AND REFERENCED_TABLE_NAME = ?
             LIMIT 1",
            [$table, $column, $referencedTable]
        );
        return $row ? $row['CONSTRAINT_NAME'] : null;
    };

    $hasCheck = function (string $table, string $constraintName) use ($db): bool {
        $row = $db->selectOne(
            "SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
             WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND CONSTRAINT_NAME = ? AND CONSTRAINT_TYPE = 'CHECK'",
            [$table, $constraintName]
        );
        return $row !== null;
    };

    echo "   Phase 32: Fixing Phase 31 deployment issues...\n";

    // ─── 1. hr_salary_components: component_type → type (CHECK blocked in Phase 31) ───
    if ($hasColumn('hr_salary_components', 'component_type') && !$hasColumn('hr_salary_components', 'type')) {
        if ($hasCheck('hr_salary_components', 'chk_hr_salary_comp_type')) {
            $safeAlter("ALTER TABLE `hr_salary_components` DROP CHECK `chk_hr_salary_comp_type`");
        }
        $safeAlter("ALTER TABLE `hr_salary_components` CHANGE COLUMN `component_type` `type` VARCHAR(20) NOT NULL DEFAULT 'earning'");
        $safeAlter("ALTER TABLE `hr_salary_components` ADD CONSTRAINT `chk_hr_salary_comp_type` CHECK (`type` IN ('earning', 'deduction'))");
        echo "      ✔ hr_salary_components: component_type → type\n";
    }

    // ─── 2. hr_holidays: religion_specific → religion (CHECK blocked in Phase 31) ───
    if ($hasColumn('hr_holidays', 'religion_specific') && !$hasColumn('hr_holidays', 'religion')) {
        if ($hasCheck('hr_holidays', 'chk_hr_holidays_religion')) {
            $safeAlter("ALTER TABLE `hr_holidays` DROP CHECK `chk_hr_holidays_religion`");
        }
        $safeAlter("ALTER TABLE `hr_holidays` CHANGE COLUMN `religion_specific` `religion` VARCHAR(20) NULL DEFAULT NULL");
        echo "      ✔ hr_holidays: religion_specific → religion\n";
    }

    // ─── 3. hr_payroll_components_log: component_type → type (CHECK blocked in Phase 31) ───
    if ($hasColumn('hr_payroll_components_log', 'component_type') && !$hasColumn('hr_payroll_components_log', 'type')) {
        if ($hasCheck('hr_payroll_components_log', 'chk_hr_payroll_comp_type')) {
            $safeAlter("ALTER TABLE `hr_payroll_components_log` DROP CHECK `chk_hr_payroll_comp_type`");
        }
        $safeAlter("ALTER TABLE `hr_payroll_components_log` CHANGE COLUMN `component_type` `type` VARCHAR(20) NOT NULL");
        $safeAlter("ALTER TABLE `hr_payroll_components_log` ADD CONSTRAINT `chk_hr_payroll_comp_type` CHECK (`type` IN ('earning', 'deduction'))");
        echo "      ✔ hr_payroll_components_log: component_type → type\n";
    }

    // ─── 4. hr_employee_loans: amount → loan_amount (CHECK blocked in Phase 31) ───
    if ($hasColumn('hr_employee_loans', 'amount') && !$hasColumn('hr_employee_loans', 'loan_amount')) {
        if ($hasCheck('hr_employee_loans', 'chk_hr_loans_amount')) {
            $safeAlter("ALTER TABLE `hr_employee_loans` DROP CHECK `chk_hr_loans_amount`");
        }
        $safeAlter("ALTER TABLE `hr_employee_loans` CHANGE COLUMN `amount` `loan_amount` DECIMAL(15,2) NOT NULL");
        $safeAlter("ALTER TABLE `hr_employee_loans` ADD CONSTRAINT `chk_hr_loans_amount` CHECK (`loan_amount` > 0)");
        echo "      ✔ hr_employee_loans: amount → loan_amount\n";
    }

    // ─── 5. Fix orphaned FKs on hr_employee_documents ───
    // Phase 31 failed to drop old FK (wrong hardcoded name), so employee_profile_id may have
    // two FKs: one to employees(id) and one to hr_employee_profiles(id). Drop the wrong one.
    $orphanFk = $findFkToTable('hr_employee_documents', 'employee_profile_id', 'employees');
    if ($orphanFk) {
        $safeAlter("ALTER TABLE `hr_employee_documents` DROP FOREIGN KEY `{$orphanFk}`");
        echo "      ✔ hr_employee_documents: dropped orphan FK '{$orphanFk}' → employees\n";
    }

    // ─── 6. Fix orphaned FKs on hr_disciplinary_actions ───
    $orphanFk = $findFkToTable('hr_disciplinary_actions', 'employee_profile_id', 'employees');
    if ($orphanFk) {
        $safeAlter("ALTER TABLE `hr_disciplinary_actions` DROP FOREIGN KEY `{$orphanFk}`");
        echo "      ✔ hr_disciplinary_actions: dropped orphan FK '{$orphanFk}' → employees\n";
    }

    // ─── 7. Add missing FK on hr_payroll_runs (Phase 31 dropped old FK but never re-added) ───
    if ($hasColumn('hr_payroll_runs', 'employee_profile_id')) {
        $existingFk = $findFkName('hr_payroll_runs', 'employee_profile_id');
        if (!$existingFk) {
            $safeAlter("ALTER TABLE `hr_payroll_runs` ADD CONSTRAINT `fk_hr_payroll_run_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
            echo "      ✔ hr_payroll_runs: added FK → hr_employee_profiles\n";
        }
    }

    // ─── 8. Add missing FK on hr_insurance_records (same issue) ───
    if ($hasColumn('hr_insurance_records', 'employee_profile_id')) {
        // Also check for orphan FK to employees table
        $orphanFk = $findFkToTable('hr_insurance_records', 'employee_profile_id', 'employees');
        if ($orphanFk) {
            $safeAlter("ALTER TABLE `hr_insurance_records` DROP FOREIGN KEY `{$orphanFk}`");
            echo "      ✔ hr_insurance_records: dropped orphan FK → employees\n";
        }
        $existingFk = $findFkToTable('hr_insurance_records', 'employee_profile_id', 'hr_employee_profiles');
        if (!$existingFk) {
            $safeAlter("ALTER TABLE `hr_insurance_records` ADD CONSTRAINT `fk_hr_insurance_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
            echo "      ✔ hr_insurance_records: added FK → hr_employee_profiles\n";
        }
    }

    // ─── 9. hr_end_of_service: employee_id → employee_profile_id ───
    if ($hasColumn('hr_end_of_service', 'employee_id') && !$hasColumn('hr_end_of_service', 'employee_profile_id')) {
        $fkName = $findFkName('hr_end_of_service', 'employee_id');
        if ($fkName) {
            $safeAlter("ALTER TABLE `hr_end_of_service` DROP FOREIGN KEY `{$fkName}`");
        }
        $safeAlter("ALTER TABLE `hr_end_of_service` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $safeAlter("ALTER TABLE `hr_end_of_service` ADD CONSTRAINT `fk_hr_eos_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
        echo "      ✔ hr_end_of_service: employee_id → employee_profile_id\n";
    }

    // ─── 10. hr_performance_reviews: employee_id → employee_profile_id ───
    if ($hasColumn('hr_performance_reviews', 'employee_id') && !$hasColumn('hr_performance_reviews', 'employee_profile_id')) {
        $fkName = $findFkName('hr_performance_reviews', 'employee_id');
        if ($fkName) {
            $safeAlter("ALTER TABLE `hr_performance_reviews` DROP FOREIGN KEY `{$fkName}`");
        }
        $safeAlter("ALTER TABLE `hr_performance_reviews` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $safeAlter("ALTER TABLE `hr_performance_reviews` ADD CONSTRAINT `fk_hr_perf_review_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
        echo "      ✔ hr_performance_reviews: employee_id → employee_profile_id\n";
    }

    // ─── 11. hr_salary_adjustments: employee_id → employee_profile_id ───
    if ($hasColumn('hr_salary_adjustments', 'employee_id') && !$hasColumn('hr_salary_adjustments', 'employee_profile_id')) {
        $fkName = $findFkName('hr_salary_adjustments', 'employee_id');
        if ($fkName) {
            $safeAlter("ALTER TABLE `hr_salary_adjustments` DROP FOREIGN KEY `{$fkName}`");
        }
        $safeAlter("ALTER TABLE `hr_salary_adjustments` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $safeAlter("ALTER TABLE `hr_salary_adjustments` ADD CONSTRAINT `fk_hr_adj_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
        echo "      ✔ hr_salary_adjustments: employee_id → employee_profile_id\n";
    }

    // ─── 12. hr_sick_leave_records: employee_id → employee_profile_id ───
    if ($hasColumn('hr_sick_leave_records', 'employee_id') && !$hasColumn('hr_sick_leave_records', 'employee_profile_id')) {
        $fkName = $findFkName('hr_sick_leave_records', 'employee_id');
        if ($fkName) {
            $safeAlter("ALTER TABLE `hr_sick_leave_records` DROP FOREIGN KEY `{$fkName}`");
        }
        $safeAlter("ALTER TABLE `hr_sick_leave_records` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $safeAlter("ALTER TABLE `hr_sick_leave_records` ADD CONSTRAINT `fk_hr_sick_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
        echo "      ✔ hr_sick_leave_records: employee_id → employee_profile_id\n";
    }

    // ─── 13. Add missing is_archived columns ───
    $archiveTables = [
        'hr_payroll_periods', 'hr_salary_components', 'hr_performance_cycles',
        'hr_performance_reviews', 'hr_salary_adjustments',
    ];
    foreach ($archiveTables as $tbl) {
        if (!$hasColumn($tbl, 'is_archived')) {
            $safeAlter("ALTER TABLE `{$tbl}` ADD COLUMN `is_archived` TINYINT(1) NOT NULL DEFAULT 0, ADD COLUMN `archived_at` TIMESTAMP NULL DEFAULT NULL, ADD COLUMN `archived_by` BIGINT UNSIGNED NULL");
            echo "      ✔ {$tbl}: added is_archived columns\n";
        }
    }

    // ─── 14. Fix hr_attendance CHECK constraint (use DROP CHECK not DROP CONSTRAINT) ───
    if ($hasCheck('hr_attendance', 'chk_hr_attendance_status')) {
        $safeAlter("ALTER TABLE `hr_attendance` DROP CHECK `chk_hr_attendance_status`");
        $safeAlter("ALTER TABLE `hr_attendance` ADD CONSTRAINT `chk_hr_attendance_status` CHECK (`status` IN ('present', 'absent', 'late', 'leave', 'holiday', 'rest_day', 'half_day'))");
        echo "      ✔ hr_attendance: updated status CHECK constraint\n";
    }

    echo "   Phase 32: Deployment fixes complete.\n";
};
