<?php

declare(strict_types=1);

/**
 * 前台（fate_site）與後台（fate_admin）Session 互通：同一 members 表內 role=admin 登入一次兩邊可用。
 */

require_once __DIR__ . DIRECTORY_SEPARATOR . 'admin_member_auth.php';

/** 後台 Session 是否已登入（須在 fate_admin session 已 start 後判斷）。 */
function fate_admin_is_logged_in(): bool
{
    return session_status() === PHP_SESSION_ACTIVE
        && session_name() === 'fate_admin'
        && !empty($_SESSION['fate_admin_member_id'])
        && (int) $_SESSION['fate_admin_member_id'] > 0;
}

function fate_session_cookie_path(): string
{
    $path = defined('FATE_SESSION_COOKIE_PATH') ? (string) FATE_SESSION_COOKIE_PATH : '/';
    $path = trim($path);

    return $path !== '' ? $path : '/';
}

/** 預設「保持登入」Cookie 有效期（秒）。 */
function fate_session_lifetime_sec(): int
{
    return defined('FATE_SESSION_LIFETIME_SEC') ? (int) FATE_SESSION_LIFETIME_SEC : 2592000;
}

/** 未勾「保持登入」時的有效期（秒）。 */
function fate_session_short_lifetime_sec(): int
{
    if (defined('FATE_SESSION_SHORT_LIFETIME_SEC')) {
        return (int) FATE_SESSION_SHORT_LIFETIME_SEC;
    }

    return min(604800, fate_session_lifetime_sec());
}

/** 登入成功前設定此 Session 的 Cookie 有效期（僅影響下一次 session_start）。 */
function fate_session_assign_cookie_lifetime(int $seconds): void
{
    $max = fate_session_lifetime_sec();
    $sec = max(3600, min($max, $seconds));
    ini_set('session.gc_maxlifetime', (string) $max);
    if (session_status() === PHP_SESSION_ACTIVE) {
        $_SESSION['fate_cookie_lifetime'] = $sec;
        fate_session_touch_cookie($sec);

        return;
    }
    $GLOBALS['fate_session_cookie_lifetime_pending'] = $sec;
}

/** 目前 Session 應使用的 Cookie 有效期。 */
function fate_session_active_cookie_lifetime(): int
{
    if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['fate_cookie_lifetime'])) {
        $v = (int) $_SESSION['fate_cookie_lifetime'];
        if ($v >= 3600) {
            return min($v, fate_session_lifetime_sec());
        }
    }
    if (isset($GLOBALS['fate_session_cookie_lifetime_pending'])) {
        $v = (int) $GLOBALS['fate_session_cookie_lifetime_pending'];
        if ($v >= 3600) {
            return min($v, fate_session_lifetime_sec());
        }
    }

    return fate_session_lifetime_sec();
}

function fate_session_is_https_request(): bool
{
    return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
        || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
}

function fate_session_is_logged_in_current(): bool
{
    if (session_status() !== PHP_SESSION_ACTIVE) {
        return false;
    }
    if (session_name() === 'fate_site') {
        return !empty($_SESSION['fate_site_member_id']) && (int) $_SESSION['fate_site_member_id'] > 0;
    }
    if (session_name() === 'fate_admin') {
        return !empty($_SESSION['fate_admin_member_id']) && (int) $_SESSION['fate_admin_member_id'] > 0;
    }

    return false;
}

/** 已登入時寫入 Session（更新檔案 mtime，避免 lazy_write 導致過早被 GC）並刷新 Cookie。 */
function fate_session_keep_alive(): void
{
    if (session_status() !== PHP_SESSION_ACTIVE || !fate_session_is_logged_in_current()) {
        return;
    }
    $_SESSION['fate_last_active'] = time();
    fate_session_touch_cookie();
}

/** session_start 前：ini 與 Cookie 參數。 */
function fate_session_apply_options(): void
{
    $gcMax = fate_session_lifetime_sec();
    $cookieLifetime = fate_session_active_cookie_lifetime();

    ini_set('session.cookie_httponly', '1');
    ini_set('session.use_strict_mode', '1');
    ini_set('session.lazy_write', '0');
    ini_set('session.gc_maxlifetime', (string) $gcMax);
    ini_set('session.cookie_lifetime', (string) $cookieLifetime);

    session_set_cookie_params([
        'lifetime' => $cookieLifetime,
        'path' => fate_session_cookie_path(),
        'domain' => '',
        'secure' => fate_session_is_https_request(),
        'httponly' => true,
        'samesite' => 'Lax',
    ]);
}

/** 已登入時刷新 Cookie 到期時間（滑動续期）。 */
function fate_session_touch_cookie(?int $lifetimeSec = null): void
{
    if (session_status() !== PHP_SESSION_ACTIVE || ini_get('session.use_cookies') !== '1') {
        return;
    }
    if (headers_sent()) {
        return;
    }

    $lifetime = $lifetimeSec ?? fate_session_active_cookie_lifetime();
    if ($lifetime <= 0) {
        return;
    }

    if (!fate_session_is_logged_in_current()) {
        return;
    }

    $p = session_get_cookie_params();
    $opts = [
        'expires' => time() + $lifetime,
        'path' => $p['path'] !== '' ? $p['path'] : fate_session_cookie_path(),
        'domain' => $p['domain'] ?? '',
        'secure' => (bool) ($p['secure'] ?? false),
        'httponly' => (bool) ($p['httponly'] ?? true),
    ];
    if (PHP_VERSION_ID >= 70300) {
        $opts['samesite'] = $p['samesite'] ?? 'Lax';
        setcookie(session_name(), session_id(), $opts);
    } else {
        setcookie(
            session_name(),
            session_id(),
            $opts['expires'],
            $opts['path'],
            $opts['domain'],
            $opts['secure'],
            $opts['httponly']
        );
    }
}

function fate_session_finalize_start(): void
{
    if (isset($GLOBALS['fate_session_cookie_lifetime_pending'])) {
        $_SESSION['fate_cookie_lifetime'] = (int) $GLOBALS['fate_session_cookie_lifetime_pending'];
        unset($GLOBALS['fate_session_cookie_lifetime_pending']);
    }
    fate_session_keep_alive();
}

function fate_admin_session_start(): void
{
    if (session_status() === PHP_SESSION_ACTIVE) {
        if (session_name() === 'fate_admin') {
            fate_session_keep_alive();

            return;
        }
        if (!headers_sent()) {
            session_write_close();
        } else {
            return;
        }
    }

    if (headers_sent()) {
        return;
    }

    fate_session_apply_options();

    session_name('fate_admin');
    session_start();
    fate_session_finalize_start();
}

function fate_member_bridge_pdo(): ?PDO
{
    try {
        require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'fate_db.php';

        return fate_bootstrap_pdo();
    } catch (Throwable) {
        return null;
    }
}

/** @param array{id:int,username:string,display_name:string,role?:string} $member */
function fate_member_is_admin_member(array $member, ?PDO $pdo = null): bool
{
    if (fate_member_role_is_admin($member['role'] ?? '')) {
        return true;
    }
    $id = (int) ($member['id'] ?? 0);
    if ($id <= 0 || !$pdo instanceof PDO) {
        return false;
    }

    return fate_member_role_is_admin(fate_member_fetch_role_by_id($pdo, $id));
}

/**
 * 讀取前台 Session 中的 admin 會員（結束時不保留 Session 開啟）。
 *
 * @return array{id:int,username:string,display_name:string,role:string}|null
 */
function fate_member_bridge_read_site_admin_member(?PDO $pdo = null): ?array
{
    require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_public_session.php';

    if (session_status() === PHP_SESSION_ACTIVE) {
        session_write_close();
    }

    fate_public_session_start();

    $id = isset($_SESSION['fate_site_member_id']) ? (int) $_SESSION['fate_site_member_id'] : 0;
    $username = isset($_SESSION['fate_site_username']) ? (string) $_SESSION['fate_site_username'] : '';
    $displayName = isset($_SESSION['fate_site_display_name']) ? (string) $_SESSION['fate_site_display_name'] : '';
    $sessionAdminFlag = !empty($_SESSION['fate_site_is_admin']);

    session_write_close();

    if ($id <= 0) {
        return null;
    }

    $pdo = $pdo instanceof PDO ? $pdo : fate_member_bridge_pdo();
    $role = '';
    if ($sessionAdminFlag) {
        $role = 'admin';
    } elseif ($pdo instanceof PDO) {
        $role = fate_member_fetch_role_by_id($pdo, $id);
    }

    if (!fate_member_role_is_admin($role)) {
        return null;
    }

    return [
        'id' => $id,
        'username' => $username,
        'display_name' => $displayName,
        'role' => 'admin',
    ];
}

/** @param array{id:int,username:string,display_name:string,role?:string} $member */
function fate_member_bridge_bind_admin_session(array $member): void
{
    if ((int) ($member['id'] ?? 0) <= 0) {
        return;
    }

    $cookieLifetime = null;
    if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['fate_cookie_lifetime'])) {
        $cookieLifetime = (int) $_SESSION['fate_cookie_lifetime'];
    }

    if (session_status() === PHP_SESSION_ACTIVE && session_name() !== 'fate_admin') {
        session_write_close();
    }

    if ($cookieLifetime !== null && $cookieLifetime >= 3600) {
        fate_session_assign_cookie_lifetime($cookieLifetime);
    }

    fate_admin_session_start();
    fate_admin_member_bind_session([
        'id' => (int) $member['id'],
        'username' => (string) ($member['username'] ?? ''),
        'display_name' => (string) ($member['display_name'] ?? ''),
    ]);
    session_write_close();
}

/** @param array{id:int,username:string,display_name:string,role?:string} $member */
function fate_member_bridge_bind_site_session(array $member): void
{
    if ((int) ($member['id'] ?? 0) <= 0) {
        return;
    }

    $cookieLifetime = null;
    if (session_status() === PHP_SESSION_ACTIVE && isset($_SESSION['fate_cookie_lifetime'])) {
        $cookieLifetime = (int) $_SESSION['fate_cookie_lifetime'];
    }

    require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_public_session.php';

    if (session_status() === PHP_SESSION_ACTIVE) {
        session_write_close();
    }

    if ($cookieLifetime !== null && $cookieLifetime >= 3600) {
        fate_session_assign_cookie_lifetime($cookieLifetime);
    }

    fate_public_session_start();
    $_SESSION['fate_site_member_id'] = (int) $member['id'];
    $_SESSION['fate_site_username'] = (string) ($member['username'] ?? '');
    $_SESSION['fate_site_display_name'] = (string) ($member['display_name'] ?? '');
    $_SESSION['fate_site_is_admin'] = fate_member_role_is_admin($member['role'] ?? 'admin');
    session_write_close();
}

/**
 * 後台尚未登入時，若前台已是 admin（Session 或 DB role），寫入 fate_admin Session。
 */
function fate_member_bridge_try_restore_admin_from_site(): bool
{
    if (fate_admin_is_logged_in()) {
        return true;
    }

    $pdo = fate_member_bridge_pdo();
    $siteMember = fate_member_bridge_read_site_admin_member($pdo);
    if ($siteMember === null) {
        return false;
    }

    fate_member_bridge_bind_admin_session($siteMember);
    fate_admin_session_start();

    return fate_admin_is_logged_in();
}

/**
 * 前台 admin 登入成功後呼叫，同步後台 Session。
 *
 * @param array{id:int,username:string,display_name:string,role?:string} $member
 */
function fate_member_bridge_sync_after_public_login(array $member): void
{
    $pdo = fate_member_bridge_pdo();
    if (!fate_member_is_admin_member($member, $pdo)) {
        return;
    }

    $member['role'] = 'admin';
    fate_member_bridge_bind_admin_session($member);

    require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_public_session.php';
    fate_public_session_start();
    $_SESSION['fate_site_is_admin'] = true;
    session_write_close();
}

/**
 * 後台 admin 登入成功後呼叫，同步前台 Session。
 *
 * @param array{id:int,username:string,display_name:string} $member
 */
function fate_member_bridge_sync_after_admin_login(array $member): void
{
    $withRole = array_merge($member, ['role' => 'admin']);
    fate_member_bridge_bind_site_session($withRole);
    fate_admin_session_start();
    fate_session_touch_cookie();
}

/** 每個後台請求啟動時嘗試還原（bootstrap 呼叫）。 */
function fate_member_bridge_bootstrap_admin_session(): void
{
    fate_admin_session_start();
    if (!fate_admin_is_logged_in()) {
        fate_member_bridge_try_restore_admin_from_site();
    }
}

function fate_member_bridge_destroy_named_session(string $sessionName): void
{
    if (session_status() === PHP_SESSION_ACTIVE && session_name() !== $sessionName) {
        session_write_close();
    }

    if ($sessionName === 'fate_admin') {
        fate_admin_session_start();
    } else {
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_public_session.php';
        fate_public_session_start();
    }

    $_SESSION = [];
    if (ini_get('session.use_cookies')) {
        $p = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000, $p['path'], $p['domain'], (bool) $p['secure'], (bool) $p['httponly']);
    }
    session_destroy();
    session_write_close();
}

/** 前台或後台登出時，兩邊 Session 一併清除。 */
function fate_member_bridge_logout_all(): void
{
    fate_member_bridge_destroy_named_session('fate_site');
    fate_member_bridge_destroy_named_session('fate_admin');
}
