<?php

namespace classes;

/**
 * Additive schema bootstrap for the Coolify infrastructure integration.
 *
 * The legacy stack has no centralized migration runner, so this class must be
 * safe to call from request handlers, cron, and tests.
 */
class coolify_schema_bootstrap
{
    private static bool $initialized = false;
    private static ?bool $tablesExist = null;

    public static function ensureTables(): void
    {
        if (self::$initialized) {
            return;
        }

        global $db;

        $queries = [
            "CREATE TABLE IF NOT EXISTS coolify_instances (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                label VARCHAR(128) NOT NULL,
                base_url VARCHAR(512) NOT NULL,
                api_token_secret TEXT NOT NULL,
                default_project_uuid VARCHAR(128) NULL,
                default_environment_uuid VARCHAR(128) NULL,
                default_environment_name VARCHAR(128) NULL,
                default_server_uuid VARCHAR(128) NULL,
                default_destination_uuid VARCHAR(128) NULL,
                status VARCHAR(32) NOT NULL DEFAULT 'unknown',
                last_checked_at DATETIME NULL,
                last_error TEXT NULL,
                created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                deleted_at DATETIME NULL,
                INDEX idx_coolify_instances_status (status),
                INDEX idx_coolify_instances_deleted_at (deleted_at)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",

            "CREATE TABLE IF NOT EXISTS coolify_targets (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                instance_id BIGINT UNSIGNED NOT NULL,
                replication_host_id BIGINT UNSIGNED NULL,
                kind VARCHAR(16) NOT NULL,
                label VARCHAR(128) NOT NULL,
                role VARCHAR(16) NOT NULL DEFAULT 'replica',
                server_uuid VARCHAR(128) NULL,
                project_uuid VARCHAR(128) NULL,
                environment_uuid VARCHAR(128) NULL,
                environment_name VARCHAR(128) NULL,
                destination_uuid VARCHAR(128) NULL,
                resource_uuid VARCHAR(128) NULL,
                resource_type VARCHAR(32) NOT NULL DEFAULT 'service',
                resource_name VARCHAR(128) NULL,
                deployment_status VARCHAR(32) NOT NULL DEFAULT 'pending',
                availability_state VARCHAR(32) NOT NULL DEFAULT 'degraded',
                desired_compose_hash CHAR(64) NULL,
                last_reconcile_status VARCHAR(32) NULL,
                last_reconcile_json LONGTEXT NULL,
                last_reconciled_at DATETIME NULL,
                options_json LONGTEXT NULL,
                created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                deleted_at DATETIME NULL,
                INDEX idx_coolify_targets_instance (instance_id),
                INDEX idx_coolify_targets_replication_host (replication_host_id),
                INDEX idx_coolify_targets_kind_status (kind, deployment_status),
                INDEX idx_coolify_targets_availability (availability_state),
                INDEX idx_coolify_targets_resource_uuid (resource_uuid),
                INDEX idx_coolify_targets_deleted_at (deleted_at)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",

            "CREATE TABLE IF NOT EXISTS coolify_operations (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                target_id BIGINT UNSIGNED NULL,
                instance_id BIGINT UNSIGNED NULL,
                operation VARCHAR(32) NOT NULL,
                status VARCHAR(32) NOT NULL DEFAULT 'running',
                guarded TINYINT(1) NOT NULL DEFAULT 1,
                message VARCHAR(512) NULL,
                error_message TEXT NULL,
                context_json LONGTEXT NULL,
                actor_user_id INT NULL,
                started_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                completed_at DATETIME NULL,
                created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                INDEX idx_coolify_operations_target (target_id),
                INDEX idx_coolify_operations_instance (instance_id),
                INDEX idx_coolify_operations_status (status),
                INDEX idx_coolify_operations_operation (operation)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",

            "CREATE TABLE IF NOT EXISTS coolify_audit_logs (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                target_id BIGINT UNSIGNED NULL,
                instance_id BIGINT UNSIGNED NULL,
                replication_host_id BIGINT UNSIGNED NULL,
                action VARCHAR(64) NOT NULL,
                actor_user_id INT NULL,
                severity VARCHAR(16) NOT NULL DEFAULT 'info',
                context_json LONGTEXT NULL,
                created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                INDEX idx_coolify_audit_target (target_id),
                INDEX idx_coolify_audit_instance (instance_id),
                INDEX idx_coolify_audit_replication_host (replication_host_id),
                INDEX idx_coolify_audit_action (action),
                INDEX idx_coolify_audit_created_at (created_at)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",

            "CREATE TABLE IF NOT EXISTS coolify_instance_gateways (
                id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                instance_id BIGINT UNSIGNED NULL,
                hostname VARCHAR(255) NOT NULL,
                target_ip VARCHAR(64) NOT NULL,
                enabled TINYINT(1) NOT NULL DEFAULT 1,
                priority INT NOT NULL DEFAULT 100,
                health_state VARCHAR(32) NOT NULL DEFAULT 'unknown',
                lb_state VARCHAR(32) NOT NULL DEFAULT 'unknown',
                last_probe_json LONGTEXT NULL,
                last_probed_at DATETIME NULL,
                last_reconciled_at DATETIME NULL,
                created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
                updated_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                deleted_at DATETIME NULL,
                UNIQUE KEY uniq_coolify_instance_gateways_target_ip (target_ip),
                INDEX idx_coolify_instance_gateways_instance (instance_id),
                INDEX idx_coolify_instance_gateways_enabled (enabled),
                INDEX idx_coolify_instance_gateways_lb_state (lb_state),
                INDEX idx_coolify_instance_gateways_deleted_at (deleted_at)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci",
        ];

        foreach ($queries as $sql) {
            $db->query($sql);
        }

        self::ensureColumn('coolify_instances', 'default_destination_uuid', 'VARCHAR(128) NULL');
        self::ensureColumn('coolify_targets', 'availability_state', "VARCHAR(32) NOT NULL DEFAULT 'degraded'");
        self::ensureColumn('coolify_targets', 'desired_compose_hash', 'CHAR(64) NULL');
        self::ensureColumn('coolify_targets', 'last_reconcile_json', 'LONGTEXT NULL');
        self::ensureColumn('coolify_operations', 'guarded', 'TINYINT(1) NOT NULL DEFAULT 1');
        self::ensureColumn('coolify_instance_gateways', 'last_reconciled_at', 'DATETIME NULL');

        self::ensureModuleConfigDefault('Coolify', 'enabled', 'false', 'bool');
        self::ensureModuleConfigDefault('Coolify', 'lb_automation_enabled', 'false', 'bool');
        self::ensureModuleConfigDefault('Coolify', 'lb_automation_mode', 'report_only', 'string');
        self::ensureModuleConfigDefault('Coolify', 'hetzner_load_balancer_id', '', 'string');
        self::ensureModuleConfigDefault('Coolify', 'hetzner_cloud_api_token', '', 'string');
        self::ensureModuleConfigDefault('Coolify', 'public_gateway_host', 'api-v2.truckwash.io', 'string');
        self::ensureModuleConfigDefault('Coolify', 'public_gateway_probe_path', '', 'string');
        self::ensureModuleConfigDefault('Coolify', 'github_runner_token', '', 'string');
        self::ensureModuleConfigDefault('Coolify', 'github_runner_service_uuid', '', 'string');
        self::ensureModuleConfigDefault('Coolify', 'github_runner_frontend_repository', 'copenhagentruckwash/pleno-vue', 'string');
        self::ensureModuleConfigDefault('Coolify', 'github_runner_backend_repository', 'copenhagentruckwash/api', 'string');
        self::ensureModuleConfigDefault('Coolify', 'github_runner_labels', 'self-hosted,Linux,X64,default', 'string');
        self::ensureModuleConfigDefault('Coolify', 'github_runner_count_per_repo', '1', 'int');

        self::ensureDefaultGateway('node1.truckwash.io', '94.130.142.41', 10);
        self::ensureDefaultGateway('node2.truckwash.io', '65.21.214.30', 20);
        self::ensureDefaultGateway('node3.truckwash.io', '23.88.23.183', 30);

        self::$initialized = true;
        self::$tablesExist = true;
    }

    public static function tablesExist(): bool
    {
        if (self::$tablesExist !== null) {
            return self::$tablesExist;
        }

        global $db;

        foreach (['coolify_instances', 'coolify_targets', 'coolify_operations', 'coolify_audit_logs', 'coolify_instance_gateways'] as $table) {
            $tableSql = $db->escape_string($table);
            $result = $db->query("SHOW TABLES LIKE '$tableSql'");
            if ($result === false || $result->num_rows === 0) {
                self::$tablesExist = false;
                return false;
            }
        }

        self::$tablesExist = true;
        return self::$tablesExist;
    }

    private static function ensureColumn(string $table, string $column, string $definition): void
    {
        global $db;

        $table = preg_replace('/[^a-zA-Z0-9_]/', '', $table);
        $column = preg_replace('/[^a-zA-Z0-9_]/', '', $column);
        if ($table === '' || $column === '') {
            return;
        }

        $result = $db->query("SHOW COLUMNS FROM `$table` LIKE '$column'");
        if ($result !== false && $result->num_rows > 0) {
            return;
        }

        $db->query("ALTER TABLE `$table` ADD COLUMN `$column` $definition");
    }

    private static function ensureModuleConfigDefault(string $module, string $variable, string $value, string $type): void
    {
        global $db;

        $moduleSql = $db->escape_string($module);
        $variableSql = $db->escape_string($variable);
        $result = $db->query("SELECT value FROM module_config WHERE module = '$moduleSql' AND variable = '$variableSql' LIMIT 1");
        if ($result !== false && $result->num_rows > 0) {
            return;
        }

        $valueSql = $db->escape_string($value);
        $typeSql = $db->escape_string($type);
        $db->query("INSERT INTO module_config (module, variable, value, type) VALUES ('$moduleSql', '$variableSql', '$valueSql', '$typeSql')");
    }

    private static function ensureDefaultGateway(string $hostname, string $targetIp, int $priority): void
    {
        global $db;

        $targetIpSql = $db->escape_string($targetIp);
        $result = $db->query("SELECT id FROM coolify_instance_gateways WHERE target_ip = '$targetIpSql' LIMIT 1");
        if ($result !== false && $result->num_rows > 0) {
            return;
        }

        $hostnameSql = $db->escape_string($hostname);
        $db->query(
            "INSERT INTO coolify_instance_gateways (hostname, target_ip, enabled, priority)
             VALUES ('$hostnameSql', '$targetIpSql', 1, " . (int)$priority . ")"
        );
    }
}
