#!/usr/bin/env python3
"""
kis_trader/scan/dart_watchlist.py — DART 임시 워치 (영구구독 아님)
"""
from __future__ import annotations

import datetime as dt
from typing import Any, Dict, List, Optional

from kis_trader.utils.env import get_env_bool, get_env_int
from kis_trader.utils.logger import get_logger

logger = get_logger("kis_trader.dart_watch")


def _now() -> dt.datetime:
    return dt.datetime.now()


def _fmt(ts: dt.datetime) -> str:
    return ts.strftime("%Y-%m-%d %H:%M:%S")


def ensure_watchlist_table(db: Any) -> None:
    db.conn.execute(
        """
        CREATE TABLE IF NOT EXISTS dart_watchlist (
            stock_code VARCHAR(20) NOT NULL PRIMARY KEY,
            corp_name VARCHAR(100) NOT NULL DEFAULT '',
            rcept_no VARCHAR(32) NOT NULL DEFAULT '',
            report_nm VARCHAR(255) NOT NULL DEFAULT '',
            added_at VARCHAR(30) NOT NULL,
            expires_at VARCHAR(30) NOT NULL,
            enabled TINYINT NOT NULL DEFAULT 1,
            KEY idx_dart_watch_exp (expires_at)
        ) CHARACTER SET utf8mb4
        """
    )


def purge_expired(db: Any) -> int:
    ensure_watchlist_table(db)
    now = _fmt(_now())
    cur = db.conn.execute(
        "DELETE FROM dart_watchlist WHERE expires_at < %s OR enabled=0",
        (now,),
    )
    try:
        return int(cur.rowcount or 0)
    except Exception:
        return 0


def list_active_watch(db: Any) -> List[Dict[str, Any]]:
    ensure_watchlist_table(db)
    purge_expired(db)
    now = _fmt(_now())
    rows = db.conn.execute(
        """
        SELECT stock_code, corp_name, rcept_no, report_nm, added_at, expires_at
        FROM dart_watchlist
        WHERE enabled=1 AND expires_at >= %s
        ORDER BY added_at DESC
        """,
        (now,),
    ).fetchall()
    return [dict(r) for r in rows]


def watch_count(db: Any) -> int:
    return len(list_active_watch(db))


def upsert_watch(
    db: Any,
    *,
    stock_code: str,
    corp_name: str = "",
    rcept_no: str = "",
    report_nm: str = "",
    ttl_hours: Optional[int] = None,
    watch_max: Optional[int] = None,
) -> bool:
    """
    구독 스위치 ON일 때만 호출. 상한 초과 시 가장 오래된 것 제거 후 삽입.
    """
    if not get_env_bool("DART_SUBSCRIBE_ENABLED", False):
        return False
    code = (stock_code or "").strip()
    if not code:
        return False
    ensure_watchlist_table(db)
    purge_expired(db)
    ttl = int(ttl_hours if ttl_hours is not None else get_env_int("DART_WATCH_TTL_HOURS", 24))
    cap = int(watch_max if watch_max is not None else get_env_int("DART_WATCH_MAX", 15))
    now = _now()
    exp = now + dt.timedelta(hours=max(1, ttl))

    active = list_active_watch(db)
    if code not in {a["stock_code"] for a in active} and len(active) >= cap:
        # 가장 오래된 1건 제거
        oldest = sorted(active, key=lambda x: x.get("added_at") or "")[:1]
        for o in oldest:
            db.conn.execute(
                "DELETE FROM dart_watchlist WHERE stock_code=%s",
                (o["stock_code"],),
            )
            logger.info("DART 워치 상한 — 제거 %s", o["stock_code"])

    db.conn.execute(
        """
        INSERT INTO dart_watchlist
            (stock_code, corp_name, rcept_no, report_nm, added_at, expires_at, enabled)
        VALUES (%s, %s, %s, %s, %s, %s, 1)
        ON DUPLICATE KEY UPDATE
            corp_name=VALUES(corp_name),
            rcept_no=VALUES(rcept_no),
            report_nm=VALUES(report_nm),
            added_at=VALUES(added_at),
            expires_at=VALUES(expires_at),
            enabled=1
        """,
        (
            code[:20],
            (corp_name or "")[:100],
            (rcept_no or "")[:32],
            (report_nm or "")[:255],
            _fmt(now),
            _fmt(exp),
        ),
    )
    return True


def event_time_for_code(db: Any, code: str) -> Optional[str]:
    """워치/최신 공시 시각 → 봉키 YYYYMMDDHHMM 근사."""
    ensure_watchlist_table(db)
    code = (code or "").strip()
    row = db.conn.execute(
        """
        SELECT added_at, rcept_no FROM dart_watchlist
        WHERE stock_code=%s AND enabled=1
        ORDER BY added_at DESC LIMIT 1
        """,
        (code,),
    ).fetchone()
    if row and row.get("added_at"):
        s = str(row["added_at"]).replace("-", "").replace(":", "").replace(" ", "")
        if len(s) >= 12:
            return s[:12]
    # disclosures fallback
    d = db.conn.execute(
        """
        SELECT first_seen_at, rcept_dt FROM dart_disclosures
        WHERE stock_code=%s ORDER BY first_seen_at DESC LIMIT 1
        """,
        (code,),
    ).fetchone()
    if not d:
        return None
    if d.get("first_seen_at"):
        s = str(d["first_seen_at"]).replace("-", "").replace(":", "").replace(" ", "")
        if len(s) >= 12:
            return s[:12]
    rd = str(d.get("rcept_dt") or "")
    if len(rd) == 8:
        return rd + "0900"
    return None
