# -*- coding: utf-8 -*-
"""每日行情 - 主入口

用法:
  python run.py                          # 抓取板块 10 和 151 当天行情
  python run.py --boards 10              # 仅抓纪念币
  python run.py --boards 151             # 仅抓纪念钞
  python run.py --date 2026-08-12        # 指定日期
  python run.py --sample --boards 151    # 仅抓样本(不解析价格)
  python run.py --force                  # 强制重抓(忽略幂等检查)
"""

from __future__ import annotations

import argparse
import os
import sys
from datetime import datetime

# 将项目根目录加入路径，以包方式导入 src
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from src import config
from src.db import Database
from src.fetcher import FetcherConfig, ForumFetcher
from src.daily_crawler import crawl_board_today, save_sample_file
from src.excel_exporter import export_daily_excel
from src.html_reporter import generate_daily_site, generate_site_index
from src.notifier import send_crawl_result


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="每日行情 - PM001 论坛纪念币/钞收购信息抓取")
    parser.add_argument("--date", default=None, help="抓取日期 YYYY-MM-DD（默认今天 Asia/Shanghai）")
    parser.add_argument("--boards", default="10,151", help="逗号分隔的板块ID（默认 10,151）")
    parser.add_argument("--sample", action="store_true", help="样本模式：仅抓取原始帖子，不解析价格")
    parser.add_argument("--force", action="store_true", help="强制重抓，忽略幂等检查")
    parser.add_argument("--max-pages", type=int, default=10, help="每个板块最多翻页数（默认 10）")
    return parser.parse_args()


def get_trade_date(date_str: str | None) -> str:
    """获取抓取日期字符串 YYYY-MM-DD"""
    if date_str:
        return date_str
    return datetime.now(config.ASIA_SHANGHAI).strftime("%Y-%m-%d")


def parse_board_ids(raw: str) -> list[int]:
    """解析逗号分隔的板块ID"""
    ids = []
    for item in raw.split(","):
        item = item.strip()
        if item:
            try:
                ids.append(int(item))
            except ValueError:
                continue
    return ids


def main() -> int:
    args = parse_args()
    trade_date = get_trade_date(args.date)
    board_ids = parse_board_ids(args.boards)

    print(f"[info] 交易日期: {trade_date}")
    print(f"[info] 目标板块: {board_ids}")
    print(f"[info] 模式: {'样本' if args.sample else '常规'}{' (强制重抓)' if args.force else ''}")

    # 初始化
    db = Database(config.DB_PATH)
    db.init_schema()

    fetcher = ForumFetcher(
        FetcherConfig(
            base_url=config.BASE_URL,
            timeout=config.TIMEOUT,
            delay_ms=config.REQUEST_DELAY_MS,
            retries=config.RETRIES,
            user_agent=config.DEFAULT_USER_AGENT,
        )
    )

    all_matched_posts = []
    board_results: list[dict] = []
    crawl_errors: list[str] = []

    try:
        for board_id in board_ids:
            board_label = config.TARGET_BOARDS.get(board_id, str(board_id))
            print(f"\n[info] 抓取板块 {board_id} ({board_label})")

            # 幂等检查
            if not args.force and not args.sample and db.is_board_crawled(trade_date, board_id):
                print(f"[info] 板块 {board_id} 当日已抓取完成，跳过（--force 可强制重抓）")
                continue

            # 抓取
            try:
                matched_posts = crawl_board_today(
                    fetcher=fetcher,
                    db=db,
                    board_id=board_id,
                    trade_date=trade_date,
                    sample_mode=args.sample,
                    max_pages=args.max_pages,
                )
            except Exception as exc:
                print(f"[error] 板块 {board_id} 抓取失败: {exc}")
                db.record_crawl_run(trade_date, board_id, "error")
                crawl_errors.append(f"{board_label}({board_id}): {exc}")
                board_results.append({
                    "board_id": board_id, "label": board_label,
                    "matched": 0, "records": 0, "status": "error",
                })
                continue

            all_matched_posts.extend(matched_posts)
            total_records = sum(len(p.coin_records) for p in matched_posts)
            print(f"[info] 板块 {board_id} 完成: 匹配帖子 {len(matched_posts)} 条, 解析记录 {total_records} 条")

            # 样本模式：写样本文件
            if args.sample and matched_posts:
                sample_path = save_sample_file(matched_posts, board_id, config.SAMPLE_DIR)
                print(f"[info] 样本已保存: {sample_path}")

            # 记录抓取状态
            status = "done" if matched_posts else "empty"
            db.record_crawl_run(trade_date, board_id, status, topic_count=len(matched_posts),
                                matched_count=total_records)
            board_results.append({
                "board_id": board_id, "label": board_label,
                "matched": len(matched_posts), "records": total_records, "status": status,
            })

        # 样本模式到此结束
        if args.sample:
            print(f"\n[done] 样本抓取完成，共 {len(all_matched_posts)} 条帖子")
            return 0

        # 导出 Excel
        excel_path = os.path.join(config.DAILY_DIR, f"每日行情_{trade_date}.xlsx")
        if all_matched_posts:
            export_daily_excel(all_matched_posts, trade_date, excel_path)
            print(f"[info] Excel 已导出: {excel_path}")
        else:
            print("[info] 无匹配帖子，跳过 Excel 导出")

        # 生成静态页面
        daily_site_dir = os.path.join(config.DAILY_DIR, trade_date)
        page_path = generate_daily_site(db, trade_date, daily_site_dir)
        print(f"[info] 当日页面已生成: {page_path}")

        # 更新站点首页
        site_index = generate_site_index(db, config.SITE_DIR)
        print(f"[info] 站点首页已更新: {site_index}")

        print(f"\n[done] 每日行情处理完成: {trade_date}")

        # 发送成功通知（有部分板块失败也算成功，但在通知中标注）
        send_crawl_result(
            trade_date=trade_date,
            board_results=board_results,
            success=True,
        )
        return 0

    except Exception as exc:
        # 未预期的异常：发送失败通知
        error_msg = "\n".join(crawl_errors + [f"未预期错误: {exc}"])
        send_crawl_result(
            trade_date=trade_date,
            board_results=board_results,
            success=False,
            error_msg=error_msg,
        )
        print(f"\n[error] 每日行情处理失败: {exc}")
        return 1

    finally:
        db.close()


if __name__ == "__main__":
    raise SystemExit(main())
