<?php
declare(strict_types=1);

use App\Core\Database;

/**
 * Phase 31: Fix column names and add missing columns to existing HR tables.
 *
 * This migration safely transforms the deployed database to match the
 * corrected schema. It checks if columns exist before renaming/adding
 * to handle partial states.
 */
return function (Database $db): void {

    /**
     * Helper: check if a column exists in a table.
     */
    $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;
    };

    /**
     * Helper: safe ALTER execution (ignores errors).
     */
    $safeAlter = function (string $sql) use ($db): void {
        try {
            $db->raw($sql);
        } catch (\Throwable $e) {
            echo "      ⚠ " . $e->getMessage() . "\n";
        }
    };

    /**
     * Helper: find FK constraint name from INFORMATION_SCHEMA.
     * Looks up the actual FK name for a given table+column pair.
     */
    $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;
    };

    /**
     * Helper: check if a CHECK constraint exists.
     */
    $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 31: Fixing HR table columns...\n";

    // ─── 1. hr_salary_structures ───
    if ($hasColumn('hr_salary_structures', 'structure_code') && !$hasColumn('hr_salary_structures', 'code')) {
        $safeAlter("ALTER TABLE `hr_salary_structures` CHANGE COLUMN `structure_code` `code` VARCHAR(30) NOT NULL");
        echo "      ✔ hr_salary_structures: structure_code → code\n";
    }
    if ($hasColumn('hr_salary_structures', 'description_ar') && !$hasColumn('hr_salary_structures', 'description')) {
        $safeAlter("ALTER TABLE `hr_salary_structures` CHANGE COLUMN `description_ar` `description` TEXT NULL");
        echo "      ✔ hr_salary_structures: description_ar → description\n";
    }
    if (!$hasColumn('hr_salary_structures', 'is_archived')) {
        $safeAlter("ALTER TABLE `hr_salary_structures` 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");
    }

    // ─── 2. hr_salary_components ───
    if ($hasColumn('hr_salary_components', 'component_type') && !$hasColumn('hr_salary_components', 'type')) {
        // Must drop CHECK constraint before renaming column (MySQL 3959)
        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";
    }
    if (!$hasColumn('hr_salary_components', 'percentage_of')) {
        $safeAlter("ALTER TABLE `hr_salary_components` ADD COLUMN `percentage_of` VARCHAR(30) NULL AFTER `calculation_type`");
    }
    if (!$hasColumn('hr_salary_components', 'percentage_value')) {
        $safeAlter("ALTER TABLE `hr_salary_components` ADD COLUMN `percentage_value` DECIMAL(5,2) NULL AFTER `percentage_of`");
    }
    if (!$hasColumn('hr_salary_components', 'is_basic')) {
        $safeAlter("ALTER TABLE `hr_salary_components` ADD COLUMN `is_basic` TINYINT(1) NOT NULL DEFAULT 0 AFTER `is_insurable`");
    }
    if (!$hasColumn('hr_salary_components', 'is_variable')) {
        $safeAlter("ALTER TABLE `hr_salary_components` ADD COLUMN `is_variable` TINYINT(1) NOT NULL DEFAULT 0 AFTER `is_basic`");
    }
    if (!$hasColumn('hr_salary_components', 'is_system_calculated')) {
        $safeAlter("ALTER TABLE `hr_salary_components` ADD COLUMN `is_system_calculated` TINYINT(1) NOT NULL DEFAULT 0 AFTER `is_variable`");
    }
    if (!$hasColumn('hr_salary_components', 'affects_overtime')) {
        $safeAlter("ALTER TABLE `hr_salary_components` ADD COLUMN `affects_overtime` TINYINT(1) NOT NULL DEFAULT 0 AFTER `is_system_calculated`");
    }

    // ─── 3. hr_employee_profiles ───
    if (!$hasColumn('hr_employee_profiles', 'first_name_ar')) {
        $safeAlter("ALTER TABLE `hr_employee_profiles` ADD COLUMN `first_name_ar` VARCHAR(100) NOT NULL DEFAULT '' AFTER `national_id`");
    }
    if (!$hasColumn('hr_employee_profiles', 'last_name_ar')) {
        $safeAlter("ALTER TABLE `hr_employee_profiles` ADD COLUMN `last_name_ar` VARCHAR(100) NOT NULL DEFAULT '' AFTER `first_name_ar`");
    }
    if (!$hasColumn('hr_employee_profiles', 'first_name_en')) {
        $safeAlter("ALTER TABLE `hr_employee_profiles` ADD COLUMN `first_name_en` VARCHAR(100) NULL AFTER `last_name_ar`");
    }
    if (!$hasColumn('hr_employee_profiles', 'last_name_en')) {
        $safeAlter("ALTER TABLE `hr_employee_profiles` ADD COLUMN `last_name_en` VARCHAR(100) NULL AFTER `first_name_en`");
    }
    if (!$hasColumn('hr_employee_profiles', 'phone')) {
        $safeAlter("ALTER TABLE `hr_employee_profiles` ADD COLUMN `phone` VARCHAR(20) NULL AFTER `last_name_en`");
    }
    if (!$hasColumn('hr_employee_profiles', 'email')) {
        $safeAlter("ALTER TABLE `hr_employee_profiles` ADD COLUMN `email` VARCHAR(200) NULL AFTER `phone`");
    }
    if (!$hasColumn('hr_employee_profiles', 'termination_type')) {
        $safeAlter("ALTER TABLE `hr_employee_profiles` ADD COLUMN `termination_type` VARCHAR(30) NULL AFTER `termination_reason`");
    }
    if (!$hasColumn('hr_employee_profiles', 'is_archived')) {
        $safeAlter("ALTER TABLE `hr_employee_profiles` 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");
    }

    // ─── 4. hr_work_schedules ───
    if ($hasColumn('hr_work_schedules', 'schedule_code') && !$hasColumn('hr_work_schedules', 'code')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` CHANGE COLUMN `schedule_code` `code` VARCHAR(30) NOT NULL");
        echo "      ✔ hr_work_schedules: schedule_code → code\n";
    }
    if ($hasColumn('hr_work_schedules', 'work_days_json') && !$hasColumn('hr_work_schedules', 'days_config_json')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` CHANGE COLUMN `work_days_json` `days_config_json` JSON NULL");
        echo "      ✔ hr_work_schedules: work_days_json → days_config_json\n";
    }
    if ($hasColumn('hr_work_schedules', 'night_shift') && !$hasColumn('hr_work_schedules', 'is_night_shift')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` CHANGE COLUMN `night_shift` `is_night_shift` TINYINT(1) NOT NULL DEFAULT 0");
        echo "      ✔ hr_work_schedules: night_shift → is_night_shift\n";
    }
    if (!$hasColumn('hr_work_schedules', 'working_days_per_week')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` ADD COLUMN `working_days_per_week` INT UNSIGNED NOT NULL DEFAULT 6 AFTER `is_night_shift`");
    }
    if (!$hasColumn('hr_work_schedules', 'hours_per_week')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` ADD COLUMN `hours_per_week` DECIMAL(4,2) NULL AFTER `working_days_per_week`");
    }
    if (!$hasColumn('hr_work_schedules', 'start_time')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` ADD COLUMN `start_time` TIME NULL, ADD COLUMN `end_time` TIME NULL");
    }
    if (!$hasColumn('hr_work_schedules', 'break_duration_minutes')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` ADD COLUMN `break_duration_minutes` INT UNSIGNED NOT NULL DEFAULT 60");
    }
    if (!$hasColumn('hr_work_schedules', 'late_tolerance_minutes')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` ADD COLUMN `late_tolerance_minutes` INT UNSIGNED NOT NULL DEFAULT 15");
    }
    if (!$hasColumn('hr_work_schedules', 'early_leave_tolerance')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` ADD COLUMN `early_leave_tolerance` INT UNSIGNED NOT NULL DEFAULT 15");
    }
    if (!$hasColumn('hr_work_schedules', 'is_archived')) {
        $safeAlter("ALTER TABLE `hr_work_schedules` 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");
    }

    // ─── 5. hr_leave_types ───
    if ($hasColumn('hr_leave_types', 'leave_code') && !$hasColumn('hr_leave_types', 'code')) {
        $safeAlter("ALTER TABLE `hr_leave_types` CHANGE COLUMN `leave_code` `code` VARCHAR(30) NOT NULL");
        echo "      ✔ hr_leave_types: leave_code → code\n";
    }
    if ($hasColumn('hr_leave_types', 'requires_document') && !$hasColumn('hr_leave_types', 'requires_attachment')) {
        $safeAlter("ALTER TABLE `hr_leave_types` CHANGE COLUMN `requires_document` `requires_attachment` TINYINT(1) NOT NULL DEFAULT 0");
    }
    if ($hasColumn('hr_leave_types', 'carry_over_max_days') && !$hasColumn('hr_leave_types', 'max_carry_over_days')) {
        $safeAlter("ALTER TABLE `hr_leave_types` CHANGE COLUMN `carry_over_max_days` `max_carry_over_days` DECIMAL(5,1) NULL");
    }
    if ($hasColumn('hr_leave_types', 'max_accumulation_years') && !$hasColumn('hr_leave_types', 'accumulation_max_years')) {
        $safeAlter("ALTER TABLE `hr_leave_types` CHANGE COLUMN `max_accumulation_years` `accumulation_max_years` INT UNSIGNED NULL DEFAULT 3");
    }
    if (!$hasColumn('hr_leave_types', 'category')) {
        $safeAlter("ALTER TABLE `hr_leave_types` ADD COLUMN `category` VARCHAR(30) NULL COMMENT 'annual, sick, special, casual, unpaid' AFTER `name_en`");
    }
    if (!$hasColumn('hr_leave_types', 'max_days_per_year')) {
        $safeAlter("ALTER TABLE `hr_leave_types` ADD COLUMN `max_days_per_year` DECIMAL(5,1) NULL AFTER `default_days_per_year`");
    }
    if (!$hasColumn('hr_leave_types', 'min_days_per_request')) {
        $safeAlter("ALTER TABLE `hr_leave_types` ADD COLUMN `min_days_per_request` DECIMAL(5,1) NULL, ADD COLUMN `max_days_per_request` DECIMAL(5,1) NULL");
    }
    if (!$hasColumn('hr_leave_types', 'min_consecutive_annual')) {
        $safeAlter("ALTER TABLE `hr_leave_types` ADD COLUMN `min_consecutive_annual` DECIMAL(5,1) NULL");
    }
    if (!$hasColumn('hr_leave_types', 'advance_notice_days')) {
        $safeAlter("ALTER TABLE `hr_leave_types` ADD COLUMN `advance_notice_days` INT UNSIGNED NOT NULL DEFAULT 0");
    }
    if (!$hasColumn('hr_leave_types', 'career_max_times')) {
        $safeAlter("ALTER TABLE `hr_leave_types` ADD COLUMN `career_max_times` INT UNSIGNED NULL, ADD COLUMN `career_max_days` DECIMAL(5,1) NULL");
    }
    if (!$hasColumn('hr_leave_types', 'legal_reference')) {
        $safeAlter("ALTER TABLE `hr_leave_types` ADD COLUMN `legal_reference` VARCHAR(100) NULL, ADD COLUMN `rules_json` JSON NULL");
    }
    if (!$hasColumn('hr_leave_types', 'is_archived')) {
        $safeAlter("ALTER TABLE `hr_leave_types` 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");
    }
    // Fix gender_restriction default
    $safeAlter("ALTER TABLE `hr_leave_types` MODIFY COLUMN `gender_restriction` VARCHAR(10) NULL DEFAULT NULL");

    // ─── 6. hr_holidays ───
    if ($hasColumn('hr_holidays', 'holiday_date') && !$hasColumn('hr_holidays', 'date')) {
        $safeAlter("ALTER TABLE `hr_holidays` CHANGE COLUMN `holiday_date` `date` DATE NULL");
        echo "      ✔ hr_holidays: holiday_date → date\n";
    }
    if ($hasColumn('hr_holidays', 'religion_specific') && !$hasColumn('hr_holidays', 'religion')) {
        // Must drop CHECK constraint before renaming column (MySQL 3959)
        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";
    }
    if (!$hasColumn('hr_holidays', 'duration_days')) {
        $safeAlter("ALTER TABLE `hr_holidays` ADD COLUMN `duration_days` INT UNSIGNED NOT NULL DEFAULT 1 AFTER `date`");
    }
    if (!$hasColumn('hr_holidays', 'is_active')) {
        $safeAlter("ALTER TABLE `hr_holidays` ADD COLUMN `is_active` TINYINT(1) NOT NULL DEFAULT 1");
    }
    if (!$hasColumn('hr_holidays', 'is_archived')) {
        $safeAlter("ALTER TABLE `hr_holidays` 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");
    }

    // ─── 7. hr_payroll_runs ───
    if ($hasColumn('hr_payroll_runs', 'employee_id') && !$hasColumn('hr_payroll_runs', 'employee_profile_id')) {
        $fkName = $findFkName('hr_payroll_runs', 'employee_id');
        if ($fkName) {
            $safeAlter("ALTER TABLE `hr_payroll_runs` DROP FOREIGN KEY `{$fkName}`");
        }
        $safeAlter("ALTER TABLE `hr_payroll_runs` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $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: employee_id → employee_profile_id\n";
    }
    if ($hasColumn('hr_payroll_runs', 'gross_salary') && !$hasColumn('hr_payroll_runs', 'gross_earnings')) {
        $safeAlter("ALTER TABLE `hr_payroll_runs` CHANGE COLUMN `gross_salary` `gross_earnings` DECIMAL(15,2) NOT NULL DEFAULT 0.00");
        echo "      ✔ hr_payroll_runs: gross_salary → gross_earnings\n";
    }
    if ($hasColumn('hr_payroll_runs', 'actual_working_days') && !$hasColumn('hr_payroll_runs', 'present_days')) {
        $safeAlter("ALTER TABLE `hr_payroll_runs` CHANGE COLUMN `actual_working_days` `present_days` INT UNSIGNED NOT NULL DEFAULT 0");
    }
    if ($hasColumn('hr_payroll_runs', 'income_tax') && !$hasColumn('hr_payroll_runs', 'tax_amount')) {
        $safeAlter("ALTER TABLE `hr_payroll_runs` CHANGE COLUMN `income_tax` `tax_amount` DECIMAL(15,2) NOT NULL DEFAULT 0.00");
    }
    if ($hasColumn('hr_payroll_runs', 'employee_insurance') && !$hasColumn('hr_payroll_runs', 'insurance_employee')) {
        $safeAlter("ALTER TABLE `hr_payroll_runs` CHANGE COLUMN `employee_insurance` `insurance_employee` DECIMAL(15,2) NOT NULL DEFAULT 0.00");
    }
    if ($hasColumn('hr_payroll_runs', 'employer_insurance') && !$hasColumn('hr_payroll_runs', 'insurance_employer')) {
        $safeAlter("ALTER TABLE `hr_payroll_runs` CHANGE COLUMN `employer_insurance` `insurance_employer` DECIMAL(15,2) NOT NULL DEFAULT 0.00");
    }
    if (!$hasColumn('hr_payroll_runs', 'total_allowances')) {
        $safeAlter("ALTER TABLE `hr_payroll_runs` ADD COLUMN `total_allowances` DECIMAL(15,2) NOT NULL DEFAULT 0.00 AFTER `gross_earnings`");
    }
    if (!$hasColumn('hr_payroll_runs', 'absence_deduction')) {
        $safeAlter("ALTER TABLE `hr_payroll_runs` ADD COLUMN `absence_deduction` DECIMAL(15,2) NOT NULL DEFAULT 0.00 AFTER `penalty_deduction`");
    }
    if (!$hasColumn('hr_payroll_runs', 'payment_reference')) {
        $safeAlter("ALTER TABLE `hr_payroll_runs` ADD COLUMN `payment_reference` VARCHAR(100) NULL AFTER `payment_method`");
    }
    if (!$hasColumn('hr_payroll_runs', 'is_archived')) {
        $safeAlter("ALTER TABLE `hr_payroll_runs` 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");
    }

    // ─── 8. hr_payroll_components_log ───
    if ($hasColumn('hr_payroll_components_log', 'component_name_ar') && !$hasColumn('hr_payroll_components_log', 'name_ar')) {
        $safeAlter("ALTER TABLE `hr_payroll_components_log` CHANGE COLUMN `component_name_ar` `name_ar` VARCHAR(200) NOT NULL");
        echo "      ✔ hr_payroll_components_log: component_name_ar → name_ar\n";
    }
    if ($hasColumn('hr_payroll_components_log', 'component_type') && !$hasColumn('hr_payroll_components_log', 'type')) {
        // Must drop CHECK constraint before renaming column (MySQL 3959)
        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";
    }

    // ─── 9. hr_insurance_records ───
    if ($hasColumn('hr_insurance_records', 'employee_id') && !$hasColumn('hr_insurance_records', 'employee_profile_id')) {
        $fkName = $findFkName('hr_insurance_records', 'employee_id');
        if ($fkName) {
            $safeAlter("ALTER TABLE `hr_insurance_records` DROP FOREIGN KEY `{$fkName}`");
        }
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $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: employee_id → employee_profile_id\n";
    }
    // Rename insurable_salary columns
    if ($hasColumn('hr_insurance_records', 'insurable_salary') && !$hasColumn('hr_insurance_records', 'basic_insurable_salary')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `insurable_salary` `basic_insurable_salary` DECIMAL(15,2) NOT NULL");
    }
    if ($hasColumn('hr_insurance_records', 'basic_salary_portion') && !$hasColumn('hr_insurance_records', 'basic_insurable_salary')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `basic_salary_portion` `basic_insurable_salary` DECIMAL(15,2) NOT NULL");
    }
    if ($hasColumn('hr_insurance_records', 'variable_salary_portion') && !$hasColumn('hr_insurance_records', 'variable_insurable_salary')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `variable_salary_portion` `variable_insurable_salary` DECIMAL(15,2) NOT NULL");
    }
    if (!$hasColumn('hr_insurance_records', 'variable_insurable_salary')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` ADD COLUMN `variable_insurable_salary` DECIMAL(15,2) NOT NULL DEFAULT 0.00 AFTER `basic_insurable_salary`");
    }
    // Rename share columns
    if ($hasColumn('hr_insurance_records', 'employee_share_basic') && !$hasColumn('hr_insurance_records', 'employee_basic_share')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `employee_share_basic` `employee_basic_share` DECIMAL(15,2) NOT NULL");
    }
    if ($hasColumn('hr_insurance_records', 'employee_share_variable') && !$hasColumn('hr_insurance_records', 'employee_variable_share')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `employee_share_variable` `employee_variable_share` DECIMAL(15,2) NOT NULL");
    }
    if ($hasColumn('hr_insurance_records', 'employer_share_basic') && !$hasColumn('hr_insurance_records', 'employer_basic_share')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `employer_share_basic` `employer_basic_share` DECIMAL(15,2) NOT NULL");
    }
    if ($hasColumn('hr_insurance_records', 'employer_share_variable') && !$hasColumn('hr_insurance_records', 'employer_variable_share')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `employer_share_variable` `employer_variable_share` DECIMAL(15,2) NOT NULL");
    }
    if ($hasColumn('hr_insurance_records', 'employee_share_total') && !$hasColumn('hr_insurance_records', 'total_employee_share')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `employee_share_total` `total_employee_share` DECIMAL(15,2) NOT NULL");
    }
    if ($hasColumn('hr_insurance_records', 'employer_share_total') && !$hasColumn('hr_insurance_records', 'total_employer_share')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` CHANGE COLUMN `employer_share_total` `total_employer_share` DECIMAL(15,2) NOT NULL");
    }
    if (!$hasColumn('hr_insurance_records', 'total_contribution')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` ADD COLUMN `total_contribution` DECIMAL(15,2) NOT NULL DEFAULT 0.00 AFTER `total_employer_share`");
    }
    if (!$hasColumn('hr_insurance_records', 'is_archived')) {
        $safeAlter("ALTER TABLE `hr_insurance_records` 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");
    }

    // ─── 10. hr_tax_records ───
    // Rename gross_taxable_income → gross_taxable_monthly
    if ($hasColumn('hr_tax_records', 'gross_taxable_income') && !$hasColumn('hr_tax_records', 'gross_taxable_monthly')) {
        $safeAlter("ALTER TABLE `hr_tax_records` CHANGE COLUMN `gross_taxable_income` `gross_taxable_monthly` DECIMAL(15,2) NOT NULL");
    }
    // Rename tax_amount → monthly_tax (if exists)
    if ($hasColumn('hr_tax_records', 'tax_amount') && !$hasColumn('hr_tax_records', 'monthly_tax')) {
        $safeAlter("ALTER TABLE `hr_tax_records` CHANGE COLUMN `tax_amount` `monthly_tax` DECIMAL(15,2) NOT NULL DEFAULT 0.00");
    }
    if (!$hasColumn('hr_tax_records', 'annual_taxable_income')) {
        $safeAlter("ALTER TABLE `hr_tax_records` ADD COLUMN `annual_taxable_income` DECIMAL(15,2) NOT NULL DEFAULT 0.00 AFTER `gross_taxable_monthly`");
    }
    if (!$hasColumn('hr_tax_records', 'annual_tax')) {
        $safeAlter("ALTER TABLE `hr_tax_records` ADD COLUMN `annual_tax` DECIMAL(15,2) NOT NULL DEFAULT 0.00 AFTER `net_taxable_income`");
    }
    if (!$hasColumn('hr_tax_records', 'month')) {
        $safeAlter("ALTER TABLE `hr_tax_records` ADD COLUMN `month` INT UNSIGNED NULL AFTER `payroll_run_id`");
    }
    // Drop total_exemptions if exists (split into personal + insurance)
    if ($hasColumn('hr_tax_records', 'total_exemptions') && $hasColumn('hr_tax_records', 'personal_exemption')) {
        $safeAlter("ALTER TABLE `hr_tax_records` DROP COLUMN `total_exemptions`");
    }
    if (!$hasColumn('hr_tax_records', 'is_archived')) {
        $safeAlter("ALTER TABLE `hr_tax_records` 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");
    }

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

    // ─── 12. hr_contracts: employee_id → employee_profile_id + column renames ───
    if ($hasColumn('hr_contracts', 'employee_id') && !$hasColumn('hr_contracts', 'employee_profile_id')) {
        $safeAlter("ALTER TABLE `hr_contracts` DROP FOREIGN KEY `fk_hr_contracts_employee`");
        $safeAlter("ALTER TABLE `hr_contracts` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $safeAlter("ALTER TABLE `hr_contracts` ADD CONSTRAINT `fk_hr_contracts_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
        echo "      ✔ hr_contracts: employee_id → employee_profile_id\n";
    }
    if ($hasColumn('hr_contracts', 'total_salary') && !$hasColumn('hr_contracts', 'total_package')) {
        $safeAlter("ALTER TABLE `hr_contracts` CHANGE COLUMN `total_salary` `total_package` DECIMAL(15,2) NOT NULL DEFAULT 0.00");
        echo "      ✔ hr_contracts: total_salary → total_package\n";
    }
    if ($hasColumn('hr_contracts', 'previous_contract_id') && !$hasColumn('hr_contracts', 'renewal_of_contract_id')) {
        $safeAlter("ALTER TABLE `hr_contracts` DROP FOREIGN KEY `fk_hr_contracts_renewal`");
        $safeAlter("ALTER TABLE `hr_contracts` CHANGE COLUMN `previous_contract_id` `renewal_of_contract_id` BIGINT UNSIGNED NULL");
        $safeAlter("ALTER TABLE `hr_contracts` ADD CONSTRAINT `fk_hr_contracts_renewal` FOREIGN KEY (`renewal_of_contract_id`) REFERENCES `hr_contracts`(`id`) ON DELETE SET NULL");
        echo "      ✔ hr_contracts: previous_contract_id → renewal_of_contract_id\n";
    }
    if ($hasColumn('hr_contracts', 'salary_structure_id')) {
        $safeAlter("ALTER TABLE `hr_contracts` DROP COLUMN `salary_structure_id`");
        echo "      ✔ hr_contracts: dropped salary_structure_id\n";
    }

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

    // ─── 14. hr_attendance: employee_id → employee_profile_id + add columns ───
    if ($hasColumn('hr_attendance', 'employee_id') && !$hasColumn('hr_attendance', 'employee_profile_id')) {
        $safeAlter("ALTER TABLE `hr_attendance` DROP FOREIGN KEY `fk_hr_attendance_employee`");
        $safeAlter("ALTER TABLE `hr_attendance` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $safeAlter("ALTER TABLE `hr_attendance` ADD CONSTRAINT `fk_hr_attendance_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
        echo "      ✔ hr_attendance: employee_id → employee_profile_id\n";
    }
    if ($hasColumn('hr_attendance', 'is_ramadan') && !$hasColumn('hr_attendance', 'is_ramadan_schedule')) {
        $safeAlter("ALTER TABLE `hr_attendance` CHANGE COLUMN `is_ramadan` `is_ramadan_schedule` TINYINT(1) NOT NULL DEFAULT 0");
        echo "      ✔ hr_attendance: is_ramadan → is_ramadan_schedule\n";
    }
    if (!$hasColumn('hr_attendance', 'is_approved')) {
        $safeAlter("ALTER TABLE `hr_attendance` ADD COLUMN `is_approved` TINYINT(1) NOT NULL DEFAULT 0");
    }
    if (!$hasColumn('hr_attendance', 'approved_by')) {
        $safeAlter("ALTER TABLE `hr_attendance` ADD COLUMN `approved_by` BIGINT UNSIGNED NULL");
    }
    if (!$hasColumn('hr_attendance', 'approved_at')) {
        $safeAlter("ALTER TABLE `hr_attendance` ADD COLUMN `approved_at` TIMESTAMP NULL DEFAULT NULL");
    }
    if (!$hasColumn('hr_attendance', 'is_archived')) {
        $safeAlter("ALTER TABLE `hr_attendance` 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");
    }
    // Update CHECK constraint to include 'late' and 'rest_day' statuses
    $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'))");

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

    // ─── 16. hr_leave_requests: employee_id → employee_profile_id + column renames ───
    if ($hasColumn('hr_leave_requests', 'employee_id') && !$hasColumn('hr_leave_requests', 'employee_profile_id')) {
        $safeAlter("ALTER TABLE `hr_leave_requests` DROP FOREIGN KEY `fk_hr_leave_req_employee`");
        $safeAlter("ALTER TABLE `hr_leave_requests` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $safeAlter("ALTER TABLE `hr_leave_requests` ADD CONSTRAINT `fk_hr_leave_req_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
        echo "      ✔ hr_leave_requests: employee_id → employee_profile_id\n";
    }
    if ($hasColumn('hr_leave_requests', 'is_half_day') && !$hasColumn('hr_leave_requests', 'half_day')) {
        $safeAlter("ALTER TABLE `hr_leave_requests` CHANGE COLUMN `is_half_day` `half_day` TINYINT(1) NOT NULL DEFAULT 0");
        echo "      ✔ hr_leave_requests: is_half_day → half_day\n";
    }
    if ($hasColumn('hr_leave_requests', 'half_day_period') && !$hasColumn('hr_leave_requests', 'half_day_type')) {
        $safeAlter("ALTER TABLE `hr_leave_requests` CHANGE COLUMN `half_day_period` `half_day_type` VARCHAR(20) NULL");
        echo "      ✔ hr_leave_requests: half_day_period → half_day_type\n";
    }
    if ($hasColumn('hr_leave_requests', 'attachment_path') && !$hasColumn('hr_leave_requests', 'document_path')) {
        $safeAlter("ALTER TABLE `hr_leave_requests` CHANGE COLUMN `attachment_path` `document_path` VARCHAR(500) NULL");
        echo "      ✔ hr_leave_requests: attachment_path → document_path\n";
    }

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

    // ─── 18. hr_employee_loans: employee_id → employee_profile_id + column renames ───
    if ($hasColumn('hr_employee_loans', 'employee_id') && !$hasColumn('hr_employee_loans', 'employee_profile_id')) {
        $safeAlter("ALTER TABLE `hr_employee_loans` DROP FOREIGN KEY `fk_hr_loans_employee`");
        $safeAlter("ALTER TABLE `hr_employee_loans` CHANGE COLUMN `employee_id` `employee_profile_id` BIGINT UNSIGNED NOT NULL");
        $safeAlter("ALTER TABLE `hr_employee_loans` ADD CONSTRAINT `fk_hr_loans_employee` FOREIGN KEY (`employee_profile_id`) REFERENCES `hr_employee_profiles`(`id`)");
        echo "      ✔ hr_employee_loans: employee_id → employee_profile_id\n";
    }
    if ($hasColumn('hr_employee_loans', 'amount') && !$hasColumn('hr_employee_loans', 'loan_amount')) {
        // Must drop CHECK constraint before renaming column (MySQL 3959)
        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";
    }
    if ($hasColumn('hr_employee_loans', 'total_installments') && !$hasColumn('hr_employee_loans', 'number_of_installments')) {
        $safeAlter("ALTER TABLE `hr_employee_loans` CHANGE COLUMN `total_installments` `number_of_installments` INT UNSIGNED NOT NULL");
        echo "      ✔ hr_employee_loans: total_installments → number_of_installments\n";
    }
    if ($hasColumn('hr_employee_loans', 'start_deduction_month') && !$hasColumn('hr_employee_loans', 'start_deduction_date')) {
        $safeAlter("ALTER TABLE `hr_employee_loans` CHANGE COLUMN `start_deduction_month` `start_deduction_date` DATE NOT NULL");
        echo "      ✔ hr_employee_loans: start_deduction_month → start_deduction_date\n";
    }
    if ($hasColumn('hr_employee_loans', 'disbursement_date') && !$hasColumn('hr_employee_loans', 'disbursed_date')) {
        $safeAlter("ALTER TABLE `hr_employee_loans` CHANGE COLUMN `disbursement_date` `disbursed_date` DATE NULL");
        echo "      ✔ hr_employee_loans: disbursement_date → disbursed_date\n";
    }
    if (!$hasColumn('hr_employee_loans', 'request_date')) {
        $safeAlter("ALTER TABLE `hr_employee_loans` ADD COLUMN `request_date` DATE NULL AFTER `interest_rate`");
    }
    if (!$hasColumn('hr_employee_loans', 'reason')) {
        $safeAlter("ALTER TABLE `hr_employee_loans` ADD COLUMN `reason` TEXT NULL AFTER `start_deduction_date`");
    }

    // ─── 19. hr_loan_installments: due_month → due_date ───
    if ($hasColumn('hr_loan_installments', 'due_month') && !$hasColumn('hr_loan_installments', 'due_date')) {
        $safeAlter("ALTER TABLE `hr_loan_installments` CHANGE COLUMN `due_month` `due_date` DATE NOT NULL");
        echo "      ✔ hr_loan_installments: due_month → due_date\n";
    }
    // Remove paid_amount/paid_date if exists, add deducted_at
    if ($hasColumn('hr_loan_installments', 'paid_amount')) {
        $safeAlter("ALTER TABLE `hr_loan_installments` DROP COLUMN `paid_amount`");
    }
    if ($hasColumn('hr_loan_installments', 'paid_date')) {
        $safeAlter("ALTER TABLE `hr_loan_installments` DROP COLUMN `paid_date`");
    }
    if (!$hasColumn('hr_loan_installments', 'deducted_at')) {
        $safeAlter("ALTER TABLE `hr_loan_installments` ADD COLUMN `deducted_at` TIMESTAMP NULL DEFAULT NULL AFTER `payroll_run_id`");
    }

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

    // ─── 21. 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";
    }

    // ─── 22. 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";
    }

    // ─── 23. 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";
    }

    // ─── 24. 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";
    }

    // ─── 25. Add missing is_archived columns to tables referenced with is_archived = 0 ───
    $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";
        }
    }

    echo "   Phase 31: HR table column fixes complete.\n";
};
