#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
数据库模块（稳定 API 门面）- SQLite

P2 / O-07：拆分 `database.py` 为稳定门面 + `db/` 分域实现。

约束：
- 外部仍通过 `import database` 调用（函数名/参数/返回结构保持不变）
- schema/migration 入口统一，避免 scattered ALTER TABLE
"""

from __future__ import annotations

import os
import threading
import time
from typing import Optional

import db_pool
from app_config import get_config
from app_logger import get_logger

from db.schema import ensure_schema
from db.migrations import migrate_database as _migrate_database
from db.admin import (
    admin_reset_user_password,
    clean_old_operation_logs,
    get_admin_by_id,
    ensure_default_admin,
    get_admin_by_username,
    get_hourly_registration_count,
    get_system_config_raw as _get_system_config_raw,
    get_system_stats,
    update_admin_password,
    update_admin_username,
    update_system_config as _update_system_config,
    verify_admin,
)
from db.accounts import (
    create_account,
    delete_account,
    delete_user_accounts,
    get_account,
    get_account_status,
    get_account_status_batch,
    get_user_accounts,
    increment_account_login_fail,
    reset_account_login_status,
    update_account_remark,
)
from db.announcements import (
    create_announcement,
    delete_announcement,
    dismiss_announcement_for_user,
    get_active_announcement_for_user,
    get_announcement_by_id,
    get_announcements,
    set_announcement_active,
)
from db.email import (
    get_user_by_email,
    get_user_email_notify,
    update_user_email,
    update_user_email_notify,
)
from db.feedbacks import (
    close_feedback,
    create_bug_feedback,
    delete_feedback,
    get_bug_feedbacks,
    get_feedback_by_id,
    get_feedback_stats,
    get_user_feedbacks,
    reply_feedback,
)
from db.passkeys import (
    count_passkeys,
    create_passkey,
    delete_passkey,
    get_passkey_by_credential_id,
    get_passkey_by_id,
    list_passkeys,
    update_passkey_usage,
)
from db.schedules import (
    clean_old_schedule_logs,
    create_schedule_execution_log,
    create_user_schedule,
    delete_schedule_logs,
    delete_user_schedule,
    get_due_user_schedules,
    get_enabled_user_schedules,
    get_schedule_by_id,
    get_schedule_execution_logs,
    get_user_all_schedule_logs,
    get_user_schedules,
    recompute_schedule_next_run,
    toggle_user_schedule,
    update_schedule_next_run,
    update_schedule_execution_log,
    update_schedule_last_run,
    update_user_schedule,
)
from db.tasks import create_task_log, delete_old_task_logs, get_task_logs, get_task_stats, get_user_run_stats
from db.users import (
    approve_user,
    cleanup_expired_social_pending_binds,
    create_user,
    create_social_pending_bind,
    delete_user,
    delete_social_login_binding,
    delete_social_pending_bind,
    extend_user_vip,
    find_social_login_binding,
    find_user_social_login_binding,
    get_all_users,
    get_users_count,
    get_pending_users,
    get_social_pending_bind,
    get_user_by_id,
    get_user_by_username,
    get_user_kdocs_settings,
    get_user_stats,
    get_user_vip_info,
    get_vip_config,
    is_user_vip,
    reject_user,
    remove_user_vip,
    set_default_vip_days,
    set_user_vip,
    list_social_login_bindings,
    update_social_login_binding_profile,
    update_user_kdocs_settings,
    upsert_social_login_binding,
    verify_user,
)
from db.security import record_login_context

config = get_config()
logger = get_logger(__name__)

# 数据库文件路径
DB_FILE = config.DB_FILE

# 数据库版本 (用于迁移管理)
DB_VERSION = 22


# ==================== 系统配置缓存（P1 / O-03） ====================

_system_config_cache_lock = threading.Lock()
_system_config_cache_value: Optional[dict] = None
_system_config_cache_loaded_at = 0.0
try:
    _SYSTEM_CONFIG_CACHE_TTL_SECONDS = float(os.environ.get("SYSTEM_CONFIG_CACHE_TTL_SECONDS", "30"))
except Exception:
    _SYSTEM_CONFIG_CACHE_TTL_SECONDS = 30.0
_SYSTEM_CONFIG_CACHE_TTL_SECONDS = max(0.0, _SYSTEM_CONFIG_CACHE_TTL_SECONDS)


def invalidate_system_config_cache() -> None:
    global _system_config_cache_value, _system_config_cache_loaded_at
    with _system_config_cache_lock:
        _system_config_cache_value = None
        _system_config_cache_loaded_at = 0.0


def _normalize_system_config_value(value) -> dict:
    try:
        return dict(value or {})
    except Exception:
        return {}


def _is_system_config_cache_valid(now_ts: float) -> bool:
    if _system_config_cache_value is None:
        return False
    if _SYSTEM_CONFIG_CACHE_TTL_SECONDS <= 0:
        return True
    return (now_ts - _system_config_cache_loaded_at) < _SYSTEM_CONFIG_CACHE_TTL_SECONDS


def _read_system_config_cache(now_ts: float, *, ignore_ttl: bool = False) -> Optional[dict]:
    with _system_config_cache_lock:
        if _system_config_cache_value is None:
            return None
        if (not ignore_ttl) and (not _is_system_config_cache_valid(now_ts)):
            return None
        return dict(_system_config_cache_value)


def _write_system_config_cache(value: dict, now_ts: float) -> None:
    global _system_config_cache_value, _system_config_cache_loaded_at
    with _system_config_cache_lock:
        _system_config_cache_value = dict(value)
        _system_config_cache_loaded_at = now_ts


def init_database():
    """初始化数据库表结构 + 迁移（入口统一）。"""
    db_pool.init_pool(DB_FILE, pool_size=config.DB_POOL_SIZE)

    with db_pool.get_db() as conn:
        ensure_schema(conn)
        _migrate_database(conn, DB_VERSION)

    ensure_default_admin()

    try:
        config_value = get_system_config()
        db_pool.configure_slow_query_runtime(threshold_ms=config_value.get("db_slow_query_ms"))
    except Exception as e:
        logger.warning(f"初始化慢查询阈值失败，使用默认值: {e}")


def migrate_database():
    """数据库迁移（对外保留接口）。"""
    with db_pool.get_db() as conn:
        ensure_schema(conn)
        _migrate_database(conn, DB_VERSION)


# ==================== 系统配置管理（缓存门面） ====================


def get_system_config():
    """获取系统配置（带进程内缓存）。"""
    now_ts = time.time()

    cached_value = _read_system_config_cache(now_ts)
    if cached_value is not None:
        return cached_value

    try:
        value = _normalize_system_config_value(_get_system_config_raw())
    except Exception:
        fallback_value = _read_system_config_cache(now_ts, ignore_ttl=True)
        if fallback_value is not None:
            return fallback_value
        raise

    _write_system_config_cache(value, now_ts)
    return dict(value)


def update_system_config(
    max_concurrent=None,
    schedule_enabled=None,
    schedule_time=None,
    schedule_browse_type=None,
    schedule_weekdays=None,
    max_concurrent_per_account=None,
    max_screenshot_concurrent=None,
    enable_screenshot=None,
    proxy_enabled=None,
    proxy_api_url=None,
    proxy_expire_minutes=None,
    auto_approve_enabled=None,
    auto_approve_hourly_limit=None,
    auto_approve_vip_days=None,
    kdocs_enabled=None,
    kdocs_doc_url=None,
    kdocs_default_unit=None,
    kdocs_sheet_name=None,
    kdocs_sheet_index=None,
    kdocs_unit_column=None,
    kdocs_image_column=None,
    kdocs_admin_notify_enabled=None,
    kdocs_admin_notify_email=None,
    kdocs_row_start=None,
    kdocs_row_end=None,
    db_slow_query_ms=None,
    social_login_enabled=None,
    social_login_endpoint=None,
    social_login_appid=None,
    social_login_appkey=None,
    social_login_providers=None,
):
    """更新系统配置（写入后立即失效缓存）。"""
    ok = _update_system_config(
        max_concurrent=max_concurrent,
        schedule_enabled=schedule_enabled,
        schedule_time=schedule_time,
        schedule_browse_type=schedule_browse_type,
        schedule_weekdays=schedule_weekdays,
        max_concurrent_per_account=max_concurrent_per_account,
        max_screenshot_concurrent=max_screenshot_concurrent,
        enable_screenshot=enable_screenshot,
        proxy_enabled=proxy_enabled,
        proxy_api_url=proxy_api_url,
        proxy_expire_minutes=proxy_expire_minutes,
        auto_approve_enabled=auto_approve_enabled,
        auto_approve_hourly_limit=auto_approve_hourly_limit,
        auto_approve_vip_days=auto_approve_vip_days,
        kdocs_enabled=kdocs_enabled,
        kdocs_doc_url=kdocs_doc_url,
        kdocs_default_unit=kdocs_default_unit,
        kdocs_sheet_name=kdocs_sheet_name,
        kdocs_sheet_index=kdocs_sheet_index,
        kdocs_unit_column=kdocs_unit_column,
        kdocs_image_column=kdocs_image_column,
        kdocs_admin_notify_enabled=kdocs_admin_notify_enabled,
        kdocs_admin_notify_email=kdocs_admin_notify_email,
        kdocs_row_start=kdocs_row_start,
        kdocs_row_end=kdocs_row_end,
        db_slow_query_ms=db_slow_query_ms,
        social_login_enabled=social_login_enabled,
        social_login_endpoint=social_login_endpoint,
        social_login_appid=social_login_appid,
        social_login_appkey=social_login_appkey,
        social_login_providers=social_login_providers,
    )
    if ok:
        invalidate_system_config_cache()
        try:
            latest_config = get_system_config()
            db_pool.configure_slow_query_runtime(threshold_ms=latest_config.get("db_slow_query_ms"))
        except Exception as e:
            logger.warning(f"更新慢查询阈值失败，保留当前配置: {e}")
    return ok
