#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations

from datetime import datetime, timedelta

import db_pool
from db.utils import get_cst_now, get_cst_now_str, sanitize_sql_like_pattern

_TASK_STATS_SELECT_SQL = """
    SELECT
        COUNT(*) as total_tasks,
        SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as success_tasks,
        SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed_tasks,
        SUM(total_items) as total_items,
        SUM(total_attachments) as total_attachments
    FROM task_logs
"""

_USER_RUN_STATS_SELECT_SQL = """
    SELECT
        SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as completed,
        SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed,
        SUM(total_items) as total_items,
        SUM(total_attachments) as total_attachments
    FROM task_logs
"""


def _build_day_bounds(date_filter: str) -> tuple[str | None, str | None]:
    """将 YYYY-MM-DD 转换为 [day_start, day_end) 区间。"""
    try:
        day_start = datetime.strptime(str(date_filter), "%Y-%m-%d")
    except Exception:
        return None, None

    day_end = day_start + timedelta(days=1)
    return day_start.strftime("%Y-%m-%d %H:%M:%S"), day_end.strftime("%Y-%m-%d %H:%M:%S")


def _normalize_int(value, default: int, *, minimum: int | None = None) -> int:
    try:
        parsed = int(value)
    except Exception:
        parsed = default
    if minimum is not None and parsed < minimum:
        return minimum
    return parsed


def _stat_value(row, key: str) -> int:
    try:
        value = row[key] if row else 0
    except Exception:
        value = 0
    return int(value or 0)


def _build_task_logs_where_sql(
    *,
    date_filter=None,
    status_filter=None,
    source_filter=None,
    user_id_filter=None,
    account_filter=None,
) -> tuple[str, list]:
    where_clauses = ["1=1"]
    params = []

    if date_filter:
        day_start, day_end = _build_day_bounds(date_filter)
        if day_start and day_end:
            where_clauses.append("tl.created_at >= ? AND tl.created_at < ?")
            params.extend([day_start, day_end])
        else:
            where_clauses.append("date(tl.created_at) = ?")
            params.append(date_filter)

    if status_filter:
        where_clauses.append("tl.status = ?")
        params.append(status_filter)

    if source_filter:
        source_filter = str(source_filter or "").strip()
        if source_filter == "user_scheduled":
            where_clauses.append("tl.source >= ? AND tl.source < ?")
            params.extend(["user_scheduled:", "user_scheduled;"])
        elif source_filter.endswith("*"):
            prefix = source_filter[:-1]
            safe_prefix = sanitize_sql_like_pattern(prefix)
            where_clauses.append("tl.source LIKE ? ESCAPE '\\\\'")
            params.append(f"{safe_prefix}%")
        else:
            where_clauses.append("tl.source = ?")
            params.append(source_filter)

    if user_id_filter:
        where_clauses.append("tl.user_id = ?")
        params.append(user_id_filter)

    if account_filter:
        safe_filter = sanitize_sql_like_pattern(account_filter)
        where_clauses.append("tl.username LIKE ? ESCAPE '\\\\'")
        params.append(f"%{safe_filter}%")

    return " AND ".join(where_clauses), params


def _fetch_task_stats_row(cursor, *, where_clause: str = "", params: tuple | list = ()) -> dict:
    sql = _TASK_STATS_SELECT_SQL
    if where_clause:
        sql = f"{sql}\nWHERE {where_clause}"
    cursor.execute(sql, params)
    row = cursor.fetchone()
    return {
        "total_tasks": _stat_value(row, "total_tasks"),
        "success_tasks": _stat_value(row, "success_tasks"),
        "failed_tasks": _stat_value(row, "failed_tasks"),
        "total_items": _stat_value(row, "total_items"),
        "total_attachments": _stat_value(row, "total_attachments"),
    }


def _fetch_user_run_stats_row(cursor, *, where_clause: str, params: tuple | list) -> dict:
    sql = f"{_USER_RUN_STATS_SELECT_SQL}\nWHERE {where_clause}"
    cursor.execute(sql, params)
    row = cursor.fetchone()
    return {
        "completed": _stat_value(row, "completed"),
        "failed": _stat_value(row, "failed"),
        "total_items": _stat_value(row, "total_items"),
        "total_attachments": _stat_value(row, "total_attachments"),
    }


def create_task_log(
    user_id,
    account_id,
    username,
    browse_type,
    status,
    total_items=0,
    total_attachments=0,
    error_message="",
    duration=None,
    source="manual",
):
    """创建任务日志记录"""
    with db_pool.get_db() as conn:
        cursor = conn.cursor()

        cursor.execute(
            """
            INSERT INTO task_logs (
                user_id, account_id, username, browse_type, status,
                total_items, total_attachments, error_message, duration, created_at, source
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """,
            (
                user_id,
                account_id,
                username,
                browse_type,
                status,
                total_items,
                total_attachments,
                error_message,
                duration,
                get_cst_now_str(),
                source,
            ),
        )

        conn.commit()
        return cursor.lastrowid


def get_task_logs(
    limit=100,
    offset=0,
    date_filter=None,
    status_filter=None,
    source_filter=None,
    user_id_filter=None,
    account_filter=None,
):
    """获取任务日志列表（支持分页和多种筛选）"""
    limit = _normalize_int(limit, 100, minimum=1)
    offset = _normalize_int(offset, 0, minimum=0)

    with db_pool.get_db() as conn:
        cursor = conn.cursor()

        where_sql, params = _build_task_logs_where_sql(
            date_filter=date_filter,
            status_filter=status_filter,
            source_filter=source_filter,
            user_id_filter=user_id_filter,
            account_filter=account_filter,
        )

        count_sql = f"""
            SELECT COUNT(*) as total
            FROM task_logs tl
            WHERE {where_sql}
        """
        cursor.execute(count_sql, params)
        total = _stat_value(cursor.fetchone(), "total")

        data_sql = f"""
            SELECT
                tl.*,
                u.username as user_username
            FROM task_logs tl
            LEFT JOIN users u ON tl.user_id = u.id
            WHERE {where_sql}
            ORDER BY tl.created_at DESC
            LIMIT ? OFFSET ?
        """
        data_params = list(params)
        data_params.extend([limit, offset])

        cursor.execute(data_sql, data_params)
        logs = [dict(row) for row in cursor.fetchall()]

        return {"logs": logs, "total": total}


def get_task_stats(date_filter=None):
    """获取任务统计信息"""
    if date_filter is None:
        date_filter = get_cst_now().strftime("%Y-%m-%d")

    day_start, day_end = _build_day_bounds(date_filter)

    with db_pool.get_db() as conn:
        cursor = conn.cursor()

        if day_start and day_end:
            today_stats = _fetch_task_stats_row(
                cursor,
                where_clause="created_at >= ? AND created_at < ?",
                params=(day_start, day_end),
            )
        else:
            today_stats = _fetch_task_stats_row(
                cursor,
                where_clause="date(created_at) = ?",
                params=(date_filter,),
            )

        total_stats = _fetch_task_stats_row(cursor)

        return {"today": today_stats, "total": total_stats}


def delete_old_task_logs(days=30, batch_size=1000):
    """删除N天前的任务日志（分批删除，避免长时间锁表）"""
    days = _normalize_int(days, 30, minimum=0)
    batch_size = _normalize_int(batch_size, 1000, minimum=1)

    cutoff = (get_cst_now() - timedelta(days=days)).strftime("%Y-%m-%d %H:%M:%S")

    total_deleted = 0
    while True:
        with db_pool.get_db() as conn:
            cursor = conn.cursor()
            cursor.execute(
                """
                DELETE FROM task_logs
                WHERE rowid IN (
                    SELECT rowid FROM task_logs
                    WHERE created_at < ?
                    LIMIT ?
                )
                """,
                (cutoff, batch_size),
            )
            deleted = cursor.rowcount
            conn.commit()

            if deleted <= 0:
                break
            total_deleted += deleted

    return total_deleted


def get_user_run_stats(user_id, date_filter=None):
    """获取用户的运行统计信息"""
    if date_filter is None:
        date_filter = get_cst_now().strftime("%Y-%m-%d")

    day_start, day_end = _build_day_bounds(date_filter)

    with db_pool.get_db() as conn:
        cursor = conn.cursor()

        if day_start and day_end:
            return _fetch_user_run_stats_row(
                cursor,
                where_clause="user_id = ? AND created_at >= ? AND created_at < ?",
                params=(user_id, day_start, day_end),
            )

        return _fetch_user_run_stats_row(
            cursor,
            where_clause="user_id = ? AND date(created_at) = ?",
            params=(user_id, date_filter),
        )
