#!/usr/bin/env python3
"""
run.py — codeNote 主程式

整合 Capture → Organize pipeline：
1. 從各來源（Memos API、本地資料夾）抓取新筆記
2. 存入 SQLite notes 資料表
3. 用 Tagger 打標（關鍵字 + 可選 LLM）
4. 用 Indexer 寫入 Obsidian vault
5. 記錄 TaggingEvent 到資料庫

用法：
    python run.py [--dry-run] [--source memos|folder] [--no-llm] [--verbose]
"""

import argparse
import sys
from datetime import datetime, timezone
from pathlib import Path

# 設定 PYTHONPATH，讓 src/ 可被 import
sys.path.insert(0, str(Path(__file__).parent))

from src.capturers.memos import MemosCapturer
from src.capturers.folder import FolderCapturer
from src.capturers.base import RawNote, BaseCapturer
from src.db.schema import init_db, get_connection
from src.db.repository import NoteRepository, TaggingEventRepository, open_repositories
from src.organizer.tagger import Tagger
from src.organizer.indexer import NoteIndexer
from src.utils.config import ConfigLoader


def parse_args():
    parser = argparse.ArgumentParser(description="codeNote pipeline runner")
    parser.add_argument(
        "--dry-run", action="store_true",
        help="只顯示會做什麼，不實際寫入檔案或 DB"
    )
    parser.add_argument(
        "--source", choices=["memos", "folder", "all"], default="all",
        help="指定只跑哪個來源（預設 all）"
    )
    parser.add_argument(
        "--no-llm", action="store_true",
        help="關閉 LLM 打標（只用關鍵字）"
    )
    parser.add_argument(
        "--verbose", "-v", action="store_true",
        help="顯示詳細輸出"
    )
    parser.add_argument(
        "--data-dir", type=Path, default=None,
        help="指定 _data/ 資料夾路徑（預設 ./Data）"
    )
    return parser.parse_args()


def log(msg: str, verbose: bool = False, is_verbose: bool = False):
    """輸出 log，is_verbose=True 的訊息只在 verbose 模式顯示"""
    if is_verbose and not verbose:
        return
    ts = datetime.now().strftime("%H:%M:%S")
    print(f"[{ts}] {msg}")


def run_pipeline(args):
    # ── 初始化 config ──
    data_dir = args.data_dir or (Path(__file__).parent / "_data")
    config_loader = ConfigLoader(data_dir=data_dir)

    log(f"📂 data_dir: {data_dir}", args.verbose)

    # ── 初始化 DB ──
    db_path = data_dir / "db" / "notes.db"
    db_path.parent.mkdir(parents=True, exist_ok=True)
    conn = init_db(db_path)
    note_repo = NoteRepository(conn)
    event_repo = TaggingEventRepository(conn)

    log(f"💾 DB: {db_path}", args.verbose)

    # ── 建立 Capturer 清單 ──
    capturers: list[BaseCapturer] = []
    registry_dir = data_dir / "registry"
    registry_dir.mkdir(parents=True, exist_ok=True)

    if args.source in ("memos", "all"):
        try:
            cfg = config_loader.load_config()
            memos_cfg = cfg.get("sources", {}).get("memos", {})
            api_url = memos_cfg.get("api_url", "http://localhost:5230")
            token = memos_cfg.get("token", "")
            capturers.append(MemosCapturer(
                base_url=api_url,
                token=token,
                registry_path=registry_dir / "memos.json"
            ))
            log("📡 MemosCapturer 加入", args.verbose)
        except Exception as e:
            log(f"⚠️  MemosCapturer 初始化失敗：{e}", args.verbose)

    if args.source in ("folder", "all"):
        try:
            cfg = config_loader.load_config()
            folder_sources = cfg.get("sources", {}).get("folders", [])
            for folder_cfg in folder_sources:
                folder_path = Path(folder_cfg.get("path", ""))
                if folder_path.exists():
                    capturers.append(FolderCapturer(
                        folder_path=folder_path,
                        extensions=folder_cfg.get("extensions", [".md", ".txt"]),
                        registry_path=registry_dir / "folder.json"
                    ))
                    log(f"📁 FolderCapturer: {folder_path}", args.verbose)
        except Exception as e:
            log(f"⚠️  FolderCapturer 初始化失敗：{e}", args.verbose)

    if not capturers:
        log("⚠️  沒有可用的 capturer，pipeline 結束", args.verbose)
        return

    # ── 抓取新筆記 ──
    tagger = Tagger(config_loader)
    indexer = NoteIndexer(config_loader)
    use_llm = not args.no_llm

    total_new = 0
    total_tagged = 0
    total_indexed = 0

    for capturer in capturers:
        source_name = capturer.__class__.__name__
        log(f"\n🔍 {source_name} — 開始抓取...", args.verbose)

        try:
            notes = capturer.fetch()
        except Exception as e:
            log(f"❌ {source_name} fetch 失敗：{e}")
            continue

        log(f"   取得 {len(notes)} 筆新 note", args.verbose)

        for note in notes:
            total_new += 1

            # 產生 note_id
            note_id = capturer.to_note_id(note)

            # 打標
            suggestions = tagger.tag(note, use_llm=use_llm)
            top_tags = tagger.top_tags(suggestions)
            total_tagged += 1

            log(
                f"   [{note_id}] tags={top_tags}",
                args.verbose, is_verbose=True
            )

            if args.dry_run:
                log(f"   [DRY-RUN] 會寫入 note_id={note_id}, tags={top_tags}")
                continue

            # 存入 DB
            content_hash = indexer.get_note_content_hash(note, top_tags)
            try:
                note_repo.upsert(
                    note_id=note_id,
                    source=note.source,
                    source_id=note.source_id,
                    created_at=note.created_at,
                    file_path="",  # 先留空，寫入 vault 後更新
                    source_url=note.source_url,
                    content_hash=content_hash,
                )
            except Exception as e:
                log(f"   ⚠️  DB upsert 失敗：{e}")

            # 寫入 vault
            try:
                filepath = indexer.index_note(note, top_tags, note_id)
                if filepath:
                    total_indexed += 1
                    # 更新 DB 的 file_path
                    conn.execute(
                        "UPDATE notes SET file_path = ? WHERE note_id = ?",
                        (str(filepath), note_id)
                    )
                    conn.commit()
                    log(
                        f"   ✅ 寫入 {filepath.name}",
                        args.verbose, is_verbose=True
                    )

                    # 記錄 TaggingEvent
                    if top_tags:
                        event_repo.insert(
                            note_id=note_id,
                            tags_suggested=top_tags,
                            method="keyword" if args.no_llm else "keyword+llm",
                        )
            except Exception as e:
                log(f"   ⚠️  vault 寫入失敗：{e}")

        # 更新 registry
        if not args.dry_run and notes:
            try:
                capturer.update_registry(notes)
            except Exception as e:
                log(f"   ⚠️  registry 更新失敗：{e}")

    # ── 摘要 ──
    log(f"\n✨ Pipeline 完成")
    log(f"   新筆記：{total_new}")
    log(f"   打標：{total_tagged}")
    log(f"   寫入 vault：{total_indexed}")
    if args.dry_run:
        log("   (DRY-RUN 模式，未實際寫入)")


if __name__ == "__main__":
    args = parse_args()
    run_pipeline(args)
