<?php
/**
 * Страница управления базой данных
 */

use Flowaxy\Core\System\PathResolver;
use Flowaxy\Support\Helpers\IniHelper;
use Flowaxy\Infrastructure\Persistence\Database\Database;

function admin_database_page() {
    // Проверка авторизации
    if (!function_exists('current_user_can') || !current_user_can('admin.settings.manage')) {
        if (function_exists('admin_redirect')) {
            admin_redirect('login');
        }
        return;
    }

    // Обработка AJAX запросов
    if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
        handle_database_ajax();
        return;
    }

    // Обработка POST запросов (подключение/отключение БД)
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
        handle_database_post();
    }

    // Получаем конфигурацию БД
    $dbConfig = get_database_config();
    $isConnected = is_database_connected();
    $dbStats = null;
    $dbTables = [];

    if ($isConnected) {
        try {
            $db = Database::getInstance();
            $dbStats = $db->getStats();
            $dbTables = get_database_tables();
        } catch (\Exception $e) {
            // Логируем ошибку, но не показываем пользователю
            if (function_exists('log_error')) {
                log_error('Database page: Failed to get stats', ['error' => $e->getMessage()]);
            }
        }
    }

    // Проверяем права доступа для кнопок управления таблицами
    $hasAdminAccess = has_database_admin_access();

    $data = [
        'dbConfig' => $dbConfig,
        'isConnected' => $isConnected,
        'dbStats' => $dbStats,
        'dbTables' => $dbTables,
        'hasAdminAccess' => $hasAdminAccess,
    ];

    $layout = [
        'title' => 'База даних - Flowaxy CMS',
        'content' => render_database_content($data),
        'pageHeaderIcon' => 'fas fa-database',
        'pageBreadcrumbs' => [
            ['title' => 'Головна', 'url' => admin_url('dashboard'), 'page' => 'dashboard'],
            ['title' => 'Налаштування', 'url' => admin_url('settings'), 'page' => 'settings'],
            ['title' => 'База даних'],
        ],
    ];

    return render_admin_layout($layout);
}

function handle_database_ajax() {
    header('Content-Type: application/json');

    if (!isset($_POST['action'])) {
        echo json_encode(['success' => false, 'message' => 'Невідома дія']);
        exit;
    }

    $action = $_POST['action'];
    $response = ['success' => false, 'message' => ''];

    switch ($action) {
        case 'test_connection':
            $response = test_database_connection();
            break;
        case 'get_tables':
            $response = get_tables_ajax();
            break;
        case 'optimize_table':
            // Проверка прав доступа
            if (!has_database_admin_access()) {
                $response = ['success' => false, 'message' => 'Недостатньо прав для виконання цієї дії'];
                break;
            }
            $tableName = $_POST['table'] ?? '';
            if (empty($tableName)) {
                $response = ['success' => false, 'message' => 'Не вказано назву таблиці'];
            } else {
                $response = optimize_database_table($tableName);
            }
            break;
        case 'truncate_table':
            // Проверка прав доступа
            if (!has_database_admin_access()) {
                $response = ['success' => false, 'message' => 'Недостатньо прав для виконання цієї дії'];
                break;
            }
            $tableName = $_POST['table'] ?? '';
            if (empty($tableName)) {
                $response = ['success' => false, 'message' => 'Не вказано назву таблиці'];
            } else {
                $response = truncate_database_table($tableName);
            }
            break;
        default:
            $response = ['success' => false, 'message' => 'Невідома дія'];
    }

    echo json_encode($response);
    exit;
}

function handle_database_post() {
    // Проверка CSRF токена
    if (!function_exists('verify_csrf_token') || !verify_csrf_token($_POST['csrf_token'] ?? null)) {
        set_flash_message('Помилка безпеки: невірний CSRF токен', 'error');
        admin_redirect('database');
        return;
    }

    $action = $_POST['action'] ?? '';

    if ($action === 'connect') {
        $host = $_POST['host'] ?? '127.0.0.1';
        $port = (int)($_POST['port'] ?? 3306);
        $name = $_POST['name'] ?? '';
        $user = $_POST['user'] ?? 'root';
        $pass = $_POST['pass'] ?? '';
        $charset = $_POST['charset'] ?? 'utf8mb4';
        $status = isset($_POST['status']) && ($_POST['status'] === '1' || $_POST['status'] === 'true' || $_POST['status'] === 'on');

        // Тестируем подключение перед сохранением
        $testResult = test_connection_params($host, $port, $name, $user, $pass, $charset);
        if (!$testResult['success']) {
            set_flash_message($testResult['message'], 'error');
            admin_redirect('database');
            return;
        }

        // Сохраняем конфигурацию
        $saved = save_database_config([
            'status' => $status ? 'true' : 'false',
            'host' => $host,
            'port' => $port,
            'name' => $name,
            'user' => $user,
            'pass' => $pass,
            'charset' => $charset,
        ]);

        if ($saved) {
            set_flash_message('Налаштування бази даних збережено', 'success');
        } else {
            set_flash_message('Помилка збереження налаштувань', 'error');
        }
    } elseif ($action === 'disconnect') {
        $saved = save_database_config(['status' => 'false'], true);
        if ($saved) {
            set_flash_message('Підключення до бази даних відключено', 'success');
        } else {
            set_flash_message('Помилка відключення', 'error');
        }
    } elseif ($action === 'optimize_table') {
        // Проверка прав доступа
        if (!has_database_admin_access()) {
            set_flash_message('Недостатньо прав для виконання цієї дії', 'error');
            admin_redirect('database');
            return;
        }

        $tableName = $_POST['table'] ?? '';
        if (empty($tableName)) {
            set_flash_message('Не вказано назву таблиці', 'error');
            admin_redirect('database');
            return;
        }

        $result = optimize_database_table($tableName);
        if ($result['success']) {
            set_flash_message('Таблиця "' . htmlspecialchars($tableName) . '" оптимізована', 'success');
        } else {
            set_flash_message('Помилка оптимізації: ' . $result['message'], 'error');
        }
    } elseif ($action === 'truncate_table') {
        // Проверка прав доступа
        if (!has_database_admin_access()) {
            set_flash_message('Недостатньо прав для виконання цієї дії', 'error');
            admin_redirect('database');
            return;
        }

        $tableName = $_POST['table'] ?? '';
        if (empty($tableName)) {
            set_flash_message('Не вказано назву таблиці', 'error');
            admin_redirect('database');
            return;
        }

        $result = truncate_database_table($tableName);
        if ($result['success']) {
            set_flash_message('Таблиця "' . htmlspecialchars($tableName) . '" очищена', 'success');
        } else {
            set_flash_message('Помилка очищення: ' . $result['message'], 'error');
        }
    }

    admin_redirect('database');
}

function get_database_config(): array {
    $configPath = PathResolver::storageConfig() . DS . 'system' . DS . 'database.ini';

    if (!file_exists($configPath)) {
        return [
            'status' => 'false',
            'host' => '127.0.0.1',
            'port' => 3306,
            'name' => '',
            'user' => 'root',
            'pass' => '',
            'charset' => 'utf8mb4',
        ];
    }

    $config = IniHelper::readFile($configPath, true);
    if ($config === false || !isset($config['database'])) {
        return [
            'status' => 'false',
            'host' => '127.0.0.1',
            'port' => 3306,
            'name' => '',
            'user' => 'root',
            'pass' => '',
            'charset' => 'utf8mb4',
        ];
    }

    return [
        'status' => $config['database']['status'] ?? 'false',
        'host' => $config['database']['host'] ?? '127.0.0.1',
        'port' => (int)($config['database']['port'] ?? 3306),
        'name' => $config['database']['name'] ?? '',
        'user' => $config['database']['user'] ?? 'root',
        'pass' => $config['database']['pass'] ?? '',
        'charset' => $config['database']['charset'] ?? 'utf8mb4',
    ];
}

function save_database_config(array $newConfig, bool $merge = true): bool {
    $configPath = PathResolver::storageConfig() . DS . 'system' . DS . 'database.ini';
    $dir = dirname($configPath);

    if (!is_dir($dir)) {
        if (!mkdir($dir, 0755, true)) {
            return false;
        }
    }

    $currentConfig = [];
    if (file_exists($configPath)) {
        $parsed = IniHelper::readFile($configPath, true);
        if ($parsed !== false && isset($parsed['database'])) {
            $currentConfig = $parsed['database'];
        }
    }

    if ($merge) {
        $config = array_merge($currentConfig, $newConfig);
    } else {
        $config = $newConfig;
    }

    // Формируем полный конфиг с комментариями
    $iniContent = "; Конфигурация базы данных\n";
    $iniContent .= "; Автоматически создано Flowaxy Framework\n\n";
    $iniContent .= "[database]\n";
    $iniContent .= "status = " . ($config['status'] ?? 'false') . "\n";
    $iniContent .= "host = " . ($config['host'] ?? '127.0.0.1') . "\n";
    $iniContent .= "port = " . ($config['port'] ?? 3306) . "\n";
    $iniContent .= "name = " . ($config['name'] ?? '') . "\n";
    $iniContent .= "user = " . ($config['user'] ?? 'root') . "\n";
    $iniContent .= "pass = " . ($config['pass'] ?? '') . "\n";
    $iniContent .= "charset = " . ($config['charset'] ?? 'utf8mb4') . "\n";

    return file_put_contents($configPath, $iniContent) !== false;
}

function is_database_connected(): bool {
    $config = get_database_config();
    $status = $config['status'] ?? 'false';
    $statusString = is_string($status) ? strtolower(trim($status)) : $status;
    $enabled = $statusString === true || $statusString === 1 || $statusString === '1' || $statusString === 'true' || $statusString === 'yes' || $statusString === 'on';

    if (!$enabled) {
        return false;
    }

    try {
        $db = Database::getInstance();
        return $db->isAvailable();
    } catch (\Exception $e) {
        return false;
    }
}

function test_connection_params(string $host, int $port, string $name, string $user, string $pass, string $charset): array {
    try {
        $dsn = sprintf('mysql:host=%s;port=%d;charset=%s', $host, $port, $charset);
        $options = [
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
            \PDO::ATTR_TIMEOUT => 5,
        ];

        $connection = new \PDO($dsn, $user, $pass, $options);

        // Проверяем существование базы данных
        if (!empty($name)) {
            $stmt = $connection->prepare('SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ?');
            $stmt->execute([$name]);
            $result = $stmt->fetch(\PDO::FETCH_ASSOC);
            if ($result === false) {
                return ['success' => false, 'message' => 'База даних "' . htmlspecialchars($name) . '" не існує'];
            }
        }

        return ['success' => true, 'message' => 'Підключення успішне'];
    } catch (\PDOException $e) {
        return ['success' => false, 'message' => 'Помилка підключення: ' . $e->getMessage()];
    } catch (\Exception $e) {
        return ['success' => false, 'message' => 'Помилка: ' . $e->getMessage()];
    }
}

function test_database_connection(): array {
    $host = $_POST['host'] ?? '';
    $port = (int)($_POST['port'] ?? 3306);
    $name = $_POST['name'] ?? '';
    $user = $_POST['user'] ?? '';
    $pass = $_POST['pass'] ?? '';
    $charset = $_POST['charset'] ?? 'utf8mb4';

    if (empty($host) || empty($user)) {
        return ['success' => false, 'message' => 'Заповніть обов\'язкові поля'];
    }

    return test_connection_params($host, $port, $name, $user, $pass, $charset);
}

function get_database_tables(): array {
    try {
        $db = Database::getInstance();
        if (!$db->isAvailable()) {
            return [];
        }

        $connection = $db->getConnection();

        // Получаем имя БД из конфигурации напрямую, а не из константы
        $dbConfig = get_database_config();
        $dbName = $dbConfig['name'] ?? '';

        // Если в конфиге нет, пробуем из константы
        if (empty($dbName) && defined('DB_NAME')) {
            $dbName = DB_NAME;
        }

        if (empty($dbName)) {
            return [];
        }

        // Пробуем получить таблицы через information_schema
        try {
            $stmt = $connection->prepare("
                SELECT
                    TABLE_NAME as name,
                    TABLE_ROWS as rows,
                    ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) as size_mb,
                    TABLE_COLLATION as collation,
                    ENGINE as engine
                FROM information_schema.TABLES
                WHERE TABLE_SCHEMA = ?
                ORDER BY TABLE_NAME
            ");
            $stmt->execute([$dbName]);
            $tables = $stmt->fetchAll(\PDO::FETCH_ASSOC);

            if (!empty($tables)) {
                return $tables;
            }
        } catch (\Exception $e) {
            // Если information_schema недоступен, используем альтернативный способ
        }

        // Альтернативный способ: используем SHOW TABLES
        try {
            // Переключаемся на нужную БД
            $connection->exec("USE `" . str_replace('`', '``', $dbName) . "`");

            $stmt = $connection->query("SHOW TABLE STATUS");
            $tables = [];

            while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
                $tables[] = [
                    'name' => $row['Name'] ?? $row['name'] ?? '',
                    'rows' => (int)($row['Rows'] ?? $row['rows'] ?? 0),
                    'size_mb' => round((($row['Data_length'] ?? $row['data_length'] ?? 0) + ($row['Index_length'] ?? $row['index_length'] ?? 0)) / 1024 / 1024, 2),
                    'collation' => $row['Collation'] ?? $row['collation'] ?? '-',
                    'engine' => $row['Engine'] ?? $row['engine'] ?? '-',
                ];
            }

            return $tables;
        } catch (\Exception $e) {
            // Логируем ошибку для диагностики
            if (function_exists('log_error')) {
                log_error('Database page: Failed to get tables (SHOW TABLE STATUS)', [
                    'error' => $e->getMessage(),
                    'db_name' => $dbName,
                ]);
            } elseif (class_exists('\Flowaxy\Support\Facades\Log')) {
                try {
                    \Flowaxy\Support\Facades\Log::Error('Database page: Failed to get tables', [
                        'exception' => $e,
                        'db_name' => $dbName,
                    ]);
                } catch (\Throwable $logError) {
                    // Ignore logging errors
                }
            }
            return [];
        }
    } catch (\Exception $e) {
        // Логируем ошибку для диагностики
        if (function_exists('log_error')) {
            log_error('Database page: Failed to get tables', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
        } elseif (class_exists('\Flowaxy\Support\Facades\Log')) {
            try {
                \Flowaxy\Support\Facades\Log::Error('Database page: Failed to get tables', [
                    'exception' => $e,
                ]);
            } catch (\Throwable $logError) {
                // Ignore logging errors
            }
        }
        return [];
    }
}

function get_tables_ajax(): array {
    $tables = get_database_tables();
    return ['success' => true, 'tables' => $tables];
}

function has_database_admin_access(): bool {
    $session = function_exists('sessionManager') ? sessionManager() : null;
    $userId = $session ? (int)($session->get('admin_user_id') ?? 0) : 0;

    // Root пользователь (userId = 0) всегда имеет доступ
    if ($userId === 0) {
        return true;
    }

    // Проверяем право admin.access
    return function_exists('current_user_can') && current_user_can('admin.access');
}

function optimize_database_table(string $tableName): array {
    try {
        $db = Database::getInstance();
        if (!$db->isAvailable()) {
            return ['success' => false, 'message' => 'База даних не підключена'];
        }

        $connection = $db->getConnection();

        // Валидация имени таблицы (только буквы, цифры, подчеркивания)
        if (!preg_match('/^[a-zA-Z0-9_]+$/', $tableName)) {
            return ['success' => false, 'message' => 'Невірна назва таблиці'];
        }

        // Выполняем OPTIMIZE TABLE
        $stmt = $connection->prepare("OPTIMIZE TABLE `" . str_replace('`', '``', $tableName) . "`");
        $stmt->execute();

        // Логируем действие
        if (function_exists('log_error')) {
            log_error('Database: Table optimized', ['table' => $tableName]);
        } elseif (class_exists('\Flowaxy\Support\Facades\Log')) {
            try {
                \Flowaxy\Support\Facades\Log::Info('Database: Table optimized', ['table' => $tableName]);
            } catch (\Throwable $logError) {
                // Ignore logging errors
            }
        }

        return ['success' => true, 'message' => 'Таблиця оптимізована'];
    } catch (\Exception $e) {
        $errorMsg = $e->getMessage();

        // Логируем ошибку
        if (function_exists('log_error')) {
            log_error('Database: Failed to optimize table', ['table' => $tableName, 'error' => $errorMsg]);
        } elseif (class_exists('\Flowaxy\Support\Facades\Log')) {
            try {
                \Flowaxy\Support\Facades\Log::Error('Database: Failed to optimize table', [
                    'table' => $tableName,
                    'exception' => $e,
                ]);
            } catch (\Throwable $logError) {
                // Ignore logging errors
            }
        }

        return ['success' => false, 'message' => $errorMsg];
    }
}

function truncate_database_table(string $tableName): array {
    try {
        $db = Database::getInstance();
        if (!$db->isAvailable()) {
            return ['success' => false, 'message' => 'База даних не підключена'];
        }

        $connection = $db->getConnection();

        // Валидация имени таблицы (только буквы, цифры, подчеркивания)
        if (!preg_match('/^[a-zA-Z0-9_]+$/', $tableName)) {
            return ['success' => false, 'message' => 'Невірна назва таблиці'];
        }

        // Выполняем TRUNCATE TABLE
        $stmt = $connection->prepare("TRUNCATE TABLE `" . str_replace('`', '``', $tableName) . "`");
        $stmt->execute();

        // Логируем действие
        if (function_exists('log_error')) {
            log_error('Database: Table truncated', ['table' => $tableName]);
        } elseif (class_exists('\Flowaxy\Support\Facades\Log')) {
            try {
                \Flowaxy\Support\Facades\Log::Info('Database: Table truncated', ['table' => $tableName]);
            } catch (\Throwable $logError) {
                // Ignore logging errors
            }
        }

        return ['success' => true, 'message' => 'Таблиця очищена'];
    } catch (\Exception $e) {
        $errorMsg = $e->getMessage();

        // Логируем ошибку
        if (function_exists('log_error')) {
            log_error('Database: Failed to truncate table', ['table' => $tableName, 'error' => $errorMsg]);
        } elseif (class_exists('\Flowaxy\Support\Facades\Log')) {
            try {
                \Flowaxy\Support\Facades\Log::Error('Database: Failed to truncate table', [
                    'table' => $tableName,
                    'exception' => $e,
                ]);
            } catch (\Throwable $logError) {
                // Ignore logging errors
            }
        }

        return ['success' => false, 'message' => $errorMsg];
    }
}

function render_database_content($data) {
    ob_start();
    $templatePath = __DIR__ . DS . 'database' . DS . 'template.php';
    if (file_exists($templatePath)) {
        extract($data);
        include $templatePath;
    }
    return ob_get_clean();
}
