"""
缺口檢測腳本：比對已收集的資料與預期交易日

使用方式：
    python -X utf8 check_gaps.py           # 檢查全部
    python -X utf8 check_gaps.py --days 7  # 檢查最近 7 天
"""
import sys
sys.stdout.reconfigure(encoding='utf-8')

import json
import argparse
from datetime import datetime, timedelta
from pathlib import Path

# 設定
BASE_DIR = Path(__file__).parent.parent
MANIFEST_FILE = BASE_DIR / "data" / "manifest.json"
RAW_DIR = BASE_DIR / "data" / "raw"

# 台灣 2026 年假日（需定期更新）
# 來源：行政院人事行政總處
HOLIDAYS_2026 = {
    "20260101",  # 元旦
    "20260102",  # 彈性放假
    "20260126",  # 除夕前一天（調整放假）
    "20260127",  # 農曆除夕
    "20260128",  # 春節
    "20260129",  # 春節
    "20260130",  # 春節
    "20260228",  # 和平紀念日
    "20260403",  # 兒童節（調整）
    "20260404",  # 清明節
    "20260501",  # 勞動節
    "20260531",  # 端午節
    "20261003",  # 中秋節
    "20261010",  # 國慶日
}


def is_trading_day(date_str: str) -> bool:
    """判斷是否為交易日（排除週末和假日）"""
    dt = datetime.strptime(date_str, "%Y%m%d")
    # 週末
    if dt.weekday() >= 5:
        return False
    # 假日
    if date_str in HOLIDAYS_2026:
        return False
    return True


def get_expected_trading_days(start_date: str, end_date: str) -> set:
    """取得期間內所有預期交易日"""
    start = datetime.strptime(start_date, "%Y%m%d")
    end = datetime.strptime(end_date, "%Y%m%d")

    days = set()
    current = start
    while current <= end:
        date_str = current.strftime("%Y%m%d")
        if is_trading_day(date_str):
            days.add(date_str)
        current += timedelta(days=1)

    return days


def get_collected_dates() -> set:
    """從 manifest.json 取得已收集的資料日期"""
    if not MANIFEST_FILE.exists():
        return set()

    with open(MANIFEST_FILE, "r", encoding="utf-8") as f:
        manifest = json.load(f)

    dates = set()
    for download in manifest.get("downloads", []):
        for date in download.get("data_dates", []):
            dates.add(date)

    return dates


def check_gaps(days: int = None):
    """檢查資料缺口"""
    print("=" * 60)
    print("SITCA 基金淨值資料缺口檢測")
    print("=" * 60)

    # 取得已收集日期
    collected = get_collected_dates()

    if not collected:
        print("\n尚無任何資料，請先執行 collector.py")
        return

    # 決定檢查範圍
    all_dates = sorted(collected)
    start_date = all_dates[0]
    end_date = datetime.now().strftime("%Y%m%d")

    if days:
        check_start = (datetime.now() - timedelta(days=days)).strftime("%Y%m%d")
        start_date = max(start_date, check_start)

    print(f"\n檢查範圍：{start_date} ~ {end_date}")

    # 計算預期交易日
    expected = get_expected_trading_days(start_date, end_date)

    # 找出缺口
    missing = expected - collected

    # 統計
    print(f"\n預期交易日：{len(expected)} 天")
    print(f"已收集日期：{len(collected & expected)} 天")
    print(f"資料缺口：{len(missing)} 天")

    if missing:
        print("\n缺少以下日期的資料：")
        for date in sorted(missing):
            dt = datetime.strptime(date, "%Y%m%d")
            weekday = ["一", "二", "三", "四", "五", "六", "日"][dt.weekday()]
            print(f"  - {date} (週{weekday})")

        print("\n注意：SITCA 僅保留最近 1-2 天資料，無法補抓歷史。")
        print("建議：記錄缺口，分析時處理 NaN 或尋找替代來源。")
    else:
        print("\n資料完整，無缺口！")

    # 顯示收集統計
    print("\n" + "=" * 60)
    print("收集統計")
    print("=" * 60)

    if MANIFEST_FILE.exists():
        with open(MANIFEST_FILE, "r", encoding="utf-8") as f:
            manifest = json.load(f)
        stats = manifest.get("stats", {})
        print(f"總檔案數：{stats.get('total_files', 0)}")
        print(f"總大小：{stats.get('total_size_human', 'N/A')}")

    return missing


def main():
    parser = argparse.ArgumentParser(description="檢測 SITCA 基金淨值資料缺口")
    parser.add_argument("--days", type=int, help="只檢查最近 N 天")
    args = parser.parse_args()

    check_gaps(args.days)


if __name__ == "__main__":
    main()
