# -*- coding: utf-8 -*-
"""/logs 命令：查看日志

支持过滤和统计，读取 ~/.abyss/logs/ 下的 JSONL 文件。

用法：
    /logs                      # 最近 20 条
    /logs -n 50                # 最近 50 条
    /logs -l error             # 仅错误（WARN/ERROR）
    /logs -c tool              # 仅工具事件
    /logs -t file_read         # 按工具过滤
    /logs --since 10m          # 最近 10 分钟
    /logs --trace a1b2c3       # 按 trace_id 串联查询
    /logs --stats              # 工具使用统计
"""
from __future__ import annotations

import gzip
import json
import re
from datetime import datetime, timedelta
from pathlib import Path
from typing import List, Optional

from ..logger import LOG_DIR


def _parse_args(args: str) -> dict:
    """解析 /logs 参数。"""
    parts = args.split() if args else []
    opts = {
        "n": 20,
        "level": None,      # -l debug/info/warn/error
        "category": None,   # -c tool/api/session/...
        "tool": None,       # -t tool_name
        "since": None,      # --since 10m/1h/1d
        "trace": None,      # --trace id
        "stats": False,     # --stats
    }
    i = 0
    while i < len(parts):
        p = parts[i]
        if p == "-n" and i + 1 < len(parts):
            try:
                opts["n"] = int(parts[i + 1])
                i += 2
                continue
            except ValueError:
                pass
        elif p == "-l" and i + 1 < len(parts):
            opts["level"] = parts[i + 1].upper()
            i += 2
            continue
        elif p == "-c" and i + 1 < len(parts):
            opts["category"] = parts[i + 1].upper()
            i += 2
            continue
        elif p == "-t" and i + 1 < len(parts):
            opts["tool"] = parts[i + 1]
            i += 2
            continue
        elif p == "--since" and i + 1 < len(parts):
            opts["since"] = parts[i + 1]
            i += 2
            continue
        elif p == "--trace" and i + 1 < len(parts):
            opts["trace"] = parts[i + 1]
            i += 2
            continue
        elif p == "--stats":
            opts["stats"] = True
            i += 1
            continue
        i += 1
    return opts


def _parse_since(since: str) -> Optional[datetime]:
    """解析 --since 参数：10m / 1h / 1d / 30s。"""
    m = re.match(r"^(\d+)([smhd])$", since)
    if not m:
        return None
    num = int(m.group(1))
    unit = m.group(2)
    delta_map = {"s": "seconds", "m": "minutes", "h": "hours", "d": "days"}
    return datetime.now() - timedelta(**{delta_map[unit]: num})


def _read_jsonl(filepath: Path) -> List[dict]:
    """读取 JSONL 文件，支持 .gz 压缩。返回 dict 列表。"""
    if not filepath.exists():
        gz = Path(str(filepath) + ".gz")
        if gz.exists():
            with gzip.open(gz, "rt", encoding="utf-8") as f:
                return [json.loads(line) for line in f if line.strip()]
        return []
    with open(filepath, "r", encoding="utf-8") as f:
        return [json.loads(line) for line in f if line.strip()]


def _collect_records(opts: dict) -> List[dict]:
    """根据过滤条件收集日志记录。"""
    since_dt = _parse_since(opts["since"]) if opts["since"] else None
    # 决定读取哪些文件
    today = datetime.now().strftime("%Y-%m-%d")
    files_to_read = []
    if since_dt:
        # 从 since_dt 到今天，逐天读取
        cur = since_dt
        end = datetime.now()
        while cur <= end:
            date_str = cur.strftime("%Y-%m-%d")
            files_to_read.append(LOG_DIR / f"abyss_{date_str}.jsonl")
            cur += timedelta(days=1)
    else:
        files_to_read.append(LOG_DIR / f"abyss_{today}.jsonl")

    records = []
    for fp in files_to_read:
        records.extend(_read_jsonl(fp))

    # 过滤
    filtered = []
    level_map = {"DEBUG": 10, "INFO": 20, "WARN": 30, "ERROR": 40}
    for rec in records:
        # 级别过滤
        if opts["level"]:
            min_num = level_map.get(opts["level"], 0)
            rec_num = level_map.get(rec.get("level", "INFO"), 20)
            if rec_num < min_num:
                continue
        # 类别过滤
        if opts["category"] and rec.get("cat", "").upper() != opts["category"]:
            continue
        # 工具过滤
        if opts["tool"] and rec.get("name", "") != opts["tool"] and rec.get("tool", "") != opts["tool"]:
            continue
        # trace_id 过滤
        if opts["trace"] and rec.get("trace_id", "") != opts["trace"]:
            continue
        # 时间过滤
        if since_dt:
            try:
                rec_ts = datetime.strptime(rec["ts"][:19], "%Y-%m-%d %H:%M:%S")
                if rec_ts < since_dt:
                    continue
            except (ValueError, KeyError):
                pass
        filtered.append(rec)

    return filtered


def _format_record(rec: dict) -> str:
    """格式化单条日志记录为可读字符串。"""
    ts = rec.get("ts", "")[:19]
    level = rec.get("level", "")
    cat = rec.get("cat", "")
    event = rec.get("event", "")
    # 构造详情
    details = []
    for key in ("name", "tool", "command", "success", "duration_ms", "error",
                "reason", "attempt", "prompt_tokens", "total_tokens", "api_ms"):
        if key in rec:
            details.append(f"{key}={rec[key]}")
    detail_str = " ".join(details)
    trace = rec.get("trace_id", "")
    trace_str = f" [{trace}]" if trace else ""
    return f"  {ts} {level:5s} {cat:11s} {event:16s} {detail_str}{trace_str}"


def _compute_stats(records: List[dict]) -> str:
    """计算工具使用统计。"""
    tool_stats = {}  # {tool_name: {total, success, fail, durations, errors}}
    for rec in records:
        if rec.get("cat") != "TOOL":
            continue
        if rec.get("event") == "end":
            name = rec.get("name") or rec.get("tool", "unknown")
            if name not in tool_stats:
                tool_stats[name] = {"total": 0, "success": 0, "fail": 0,
                                    "durations": [], "errors": {}}
            s = tool_stats[name]
            s["total"] += 1
            if rec.get("success"):
                s["success"] += 1
            else:
                s["fail"] += 1
            dur = rec.get("duration_ms", 0)
            s["durations"].append(dur)
        elif rec.get("event") == "correction":
            name = rec.get("tool", "unknown")
            if name not in tool_stats:
                tool_stats[name] = {"total": 0, "success": 0, "fail": 0,
                                    "durations": [], "errors": {}}
            tool_stats[name].setdefault("corrections", 0)
            tool_stats[name]["corrections"] = tool_stats[name].get("corrections", 0) + 1

    if not tool_stats:
        return "  [INFO] 无工具调用记录"

    lines = ["工具使用统计：", ""]
    lines.append(f"  {'工具':<20s} {'调用':>6s} {'成功':>6s} {'失败':>6s} {'成功率':>8s} {'平均ms':>8s} {'P95ms':>8s} {'自纠错':>6s}")
    lines.append("  " + "-" * 90)
    for name in sorted(tool_stats.keys(), key=lambda n: tool_stats[n]["total"], reverse=True):
        s = tool_stats[name]
        total = s["total"]
        success = s["success"]
        fail = s["fail"]
        rate = f"{success/total*100:.1f}%" if total else "0%"
        durations = sorted(s["durations"]) if s["durations"] else [0]
        avg = sum(durations) // len(durations) if durations else 0
        # P95: 第 95 百分位
        p95_idx = int(len(durations) * 0.95)
        p95 = durations[min(p95_idx, len(durations) - 1)]
        corrections = s.get("corrections", 0)
        lines.append(
            f"  {name:<20s} {total:>6d} {success:>6d} {fail:>6d} {rate:>8s} {avg:>8d} {p95:>8d} {corrections:>6d}"
        )

    # 失败原因 Top5
    all_errors = {}
    for rec in records:
        if rec.get("cat") == "TOOL" and rec.get("event") == "end" and not rec.get("success"):
            err = rec.get("error", "未知错误")[:60]
            all_errors[err] = all_errors.get(err, 0) + 1
    if all_errors:
        lines.append("")
        lines.append("失败原因 Top5：")
        for err, count in sorted(all_errors.items(), key=lambda x: -x[1])[:5]:
            lines.append(f"  {count:>4d}x  {err}")

    return "\n".join(lines)


def handle_logs(args: str = "") -> str:
    """/logs 命令处理：查看日志。

    Args:
        args: 命令参数（如 "-n 50 -l error"）

    Returns:
        可读的日志字符串
    """
    opts = _parse_args(args)

    # 检查日志目录
    if not LOG_DIR.exists():
        return "[INFO] 日志目录不存在，尚无日志记录"

    # 收集记录
    try:
        records = _collect_records(opts)
    except Exception as e:
        return f"[ERR] 读取日志失败: {e}"

    if not records:
        return "[INFO] 无匹配的日志记录"

    # 统计模式
    if opts["stats"]:
        return _compute_stats(records)

    # 默认：显示最近 N 条
    n = opts["n"]
    recent = records[-n:] if len(records) > n else records

    lines = [f"最近 {len(recent)} 条日志（共 {len(records)} 条匹配）：", ""]
    for rec in recent:
        lines.append(_format_record(rec))

    return "\n".join(lines)
