<?php

declare(strict_types=1);

/**
 * 建立 FATE 站台的資料庫連線並回傳 PDO。
 *
 * 設定來源依序嘗試（先找到者優先）：
 *   1) 環境變數 FATE_DB_HOST / FATE_DB_NAME / FATE_DB_USER / FATE_DB_PASS / FATE_DB_CHARSET
 *   2) 本機設定檔 fate/config/db.php（請複製 config/db.example.php 後填寫；勿提交版本庫）
 *   3) 舊版相容：同層 ../newbies/db_connect.php（若存在，沿用其 $pdo）
 *
 * 三者皆無時拋出例外，提示如何設定。
 */
require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_path_safe.php';

if (!function_exists('fate_db_configured_database_name')) {
    /** 解析 FATE 主資料庫名稱（環境變數 → config/db.php → 本機預設 fate） */
    function fate_db_configured_database_name(): string
    {
        foreach (['FATE_MEMBER_DATABASE', 'FATE_DB_NAME'] as $envKey) {
            $fromEnv = getenv($envKey);
            if (is_string($fromEnv) && trim($fromEnv) !== '') {
                return trim($fromEnv);
            }
        }

        $localCfg = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'db.php';
        if (is_file($localCfg)) {
            try {
                /** @var mixed $cfg */
                $cfg = require $localCfg;
                if (is_array($cfg) && isset($cfg['name']) && trim((string) $cfg['name']) !== '') {
                    return trim((string) $cfg['name']);
                }
            } catch (Throwable) {
                /* 略過 */
            }
        }

        return 'fate';
    }
}

if (!function_exists('fate_db_pdo_current_database')) {
    function fate_db_pdo_current_database(PDO $pdo): ?string
    {
        try {
            $name = $pdo->query('SELECT DATABASE()')->fetchColumn();
            if (is_string($name) && trim($name) !== '') {
                return trim($name);
            }
        } catch (Throwable) {
            /* 略過 */
        }

        return null;
    }
}

if (!function_exists('fate_db_pdo_from_parts')) {
    function fate_db_pdo_from_parts(
        string $host,
        string $name,
        string $user,
        string $pass,
        string $charset = 'utf8mb4'
    ): PDO {
        $charset = $charset !== '' ? $charset : 'utf8mb4';
        $dsn = 'mysql:host=' . $host . ';dbname=' . $name . ';charset=' . $charset;

        return new PDO($dsn, $user, $pass, [
            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES   => false,
        ]);
    }
}

/** @return 'env'|'file'|'legacy'|'missing' */
function fate_db_config_source(): string
{
    $envHost = getenv('FATE_DB_HOST');
    if (is_string($envHost) && trim($envHost) !== '') {
        return 'env';
    }

    $localCfg = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'db.php';
    if (is_file($localCfg)) {
        return 'file';
    }

    $legacy = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'newbies' . DIRECTORY_SEPARATOR . 'db_connect.php';
    if (fate_path_is_file_safe($legacy)) {
        return 'legacy';
    }

    return 'missing';
}

/** @return array{source:string,host:string,name:string,user:string,config_path:string} */
function fate_db_config_summary(): array
{
    $source = fate_db_config_source();
    $localCfg = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'db.php';

    if ($source === 'env') {
        return [
            'source' => 'env',
            'host' => trim((string) (getenv('FATE_DB_HOST') ?: '')),
            'name' => fate_db_configured_database_name(),
            'user' => (string) (getenv('FATE_DB_USER') ?: ''),
            'config_path' => '',
        ];
    }

    if ($source === 'file') {
        /** @var mixed $cfg */
        $cfg = require $localCfg;

        return [
            'source' => 'file',
            'host' => is_array($cfg) ? (string) ($cfg['host'] ?? '') : '',
            'name' => is_array($cfg) && trim((string) ($cfg['name'] ?? '')) !== ''
                ? trim((string) $cfg['name'])
                : fate_db_configured_database_name(),
            'user' => is_array($cfg) ? (string) ($cfg['user'] ?? '') : '',
            'config_path' => $localCfg,
        ];
    }

    return [
        'source' => $source,
        'host' => '',
        'name' => fate_db_configured_database_name(),
        'user' => '',
        'config_path' => $localCfg,
    ];
}

if (!function_exists('fate_db_make_pdo')) {
    function fate_db_make_pdo(): PDO
    {
        // 1) 環境變數
        $envHost = getenv('FATE_DB_HOST');
        if (is_string($envHost) && trim($envHost) !== '') {
            return fate_db_pdo_from_parts(
                $envHost,
                fate_db_configured_database_name(),
                (string) (getenv('FATE_DB_USER') ?: ''),
                (string) (getenv('FATE_DB_PASS') ?: ''),
                (string) (getenv('FATE_DB_CHARSET') ?: 'utf8mb4')
            );
        }

        // 2) 本機設定檔 config/db.php（回傳關聯陣列）
        $localCfg = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'db.php';
        if (is_file($localCfg)) {
            /** @var mixed $cfg */
            $cfg = require $localCfg;
            if (is_array($cfg) && isset($cfg['host'])) {
                return fate_db_pdo_from_parts(
                    (string) $cfg['host'],
                    trim((string) ($cfg['name'] ?? '')) !== ''
                        ? trim((string) $cfg['name'])
                        : fate_db_configured_database_name(),
                    (string) ($cfg['user'] ?? ''),
                    (string) ($cfg['pass'] ?? ''),
                    (string) ($cfg['charset'] ?? 'utf8mb4')
                );
            }
            // 若設定檔自行建立了 $pdo（舊式寫法），亦接受
            if (isset($pdo) && $pdo instanceof PDO) {
                return $pdo;
            }
        }

        // 3) 舊版相容：sibling 專案 newbies/db_connect.php
        $legacy = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'newbies' . DIRECTORY_SEPARATOR . 'db_connect.php';
        if (fate_path_is_file_safe($legacy)) {
            require $legacy;
            if (isset($pdo) && $pdo instanceof PDO) {
                return $pdo;
            }
        }

        throw new RuntimeException(
            '找不到資料庫設定：請複製 fate/config/db.example.php 為 fate/config/db.php 並填入連線資訊，'
            . '或設定 FATE_DB_HOST/FATE_DB_NAME/FATE_DB_USER/FATE_DB_PASS 環境變數。'
        );
    }
}

if (!function_exists('fate_db_credentials')) {
    /** @return array{host:string,name:string,user:string,pass:string,charset:string,source:string}|null */
    function fate_db_credentials(): ?array
    {
        $envHost = getenv('FATE_DB_HOST');
        if (is_string($envHost) && trim($envHost) !== '') {
            return [
                'host' => trim($envHost),
                'name' => fate_db_configured_database_name(),
                'user' => (string) (getenv('FATE_DB_USER') ?: ''),
                'pass' => (string) (getenv('FATE_DB_PASS') ?: ''),
                'charset' => (string) (getenv('FATE_DB_CHARSET') ?: 'utf8mb4'),
                'source' => 'env',
            ];
        }

        $localCfg = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'db.php';
        if (is_file($localCfg)) {
            /** @var mixed $cfg */
            $cfg = require $localCfg;
            if (is_array($cfg) && isset($cfg['host'])) {
                return [
                    'host' => (string) ($cfg['host'] ?? ''),
                    'name' => trim((string) ($cfg['name'] ?? '')) !== ''
                        ? trim((string) $cfg['name'])
                        : fate_db_configured_database_name(),
                    'user' => (string) ($cfg['user'] ?? ''),
                    'pass' => (string) ($cfg['pass'] ?? ''),
                    'charset' => (string) ($cfg['charset'] ?? 'utf8mb4'),
                    'source' => 'file',
                ];
            }
        }

        if (fate_db_config_source() === 'legacy') {
            return [
                'host' => '',
                'name' => fate_db_configured_database_name(),
                'user' => '',
                'pass' => '',
                'charset' => 'utf8mb4',
                'source' => 'legacy',
            ];
        }

        return null;
    }
}

/** 連線 MySQL 伺服器（不指定資料庫），供安裝精靈建立資料庫用。 */
if (!function_exists('fate_db_pdo_without_database')) {
    function fate_db_pdo_without_database(?string &$connectError = null): ?PDO
    {
        $cred = fate_db_credentials();
        if ($cred === null || $cred['host'] === '') {
            $connectError = '找不到資料庫設定';

            return null;
        }

        $charset = $cred['charset'] !== '' ? $cred['charset'] : 'utf8mb4';
        $dsn = 'mysql:host=' . $cred['host'] . ';charset=' . $charset;

        try {
            return new PDO($dsn, $cred['user'], $cred['pass'], [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            ]);
        } catch (Throwable $e) {
            $connectError = $e->getMessage();

            return null;
        }
    }
}
