"""
學術期刊論文監控系統 - 研究筆記自動生成模組（Phase 11）

將高優先級論文自動轉為 Research Zoo 論文筆記。
生成的筆記存放在 papers/ 資料夾，與 research/ 明確區隔。

功能：
- 自動建立論文筆記（Markdown 格式）
- LLM 生成：中文翻譯、方法論摘要、關聯分析
- 與凱文論文的相關性評估
- 自動填入 YAML metadata

輸出路徑：
  papers/YYYY/MM/YYYY-MM-DD-論文標題.md

重要區隔：
  - papers/ → 自動生成，待驗證
  - research/ → 人工發起，高價值
"""

import sys
sys.stdout.reconfigure(encoding='utf-8')

import json
import logging
import re
import sqlite3
from datetime import datetime
from pathlib import Path
from typing import Optional

from config import DATABASE_PATH, JOURNALS
from llm_analyzer import call_claude_cli

logger = logging.getLogger(__name__)

# ============================================================
# 路徑設定
# ============================================================

# Research Zoo 根目錄
RESEARCH_ZOO_ROOT = Path(__file__).parent.parent.parent
PAPERS_DIR = RESEARCH_ZOO_ROOT / "papers"

# ============================================================
# LLM 提示詞
# ============================================================

NOTE_GENERATION_PROMPT = """你是一位學術研究助理，正在幫助凱文（政大 MBA 學生）整理論文筆記。
凱文的論文方向是：氣候實體風險對台灣房價的影響。

請根據以下論文資訊，生成結構化的論文筆記內容。

論文資訊：
標題：{title}
期刊：{journal}
作者：{authors}
DOI：{doi}
發表日期：{publication_date}

摘要：
{abstract}

---

請用繁體中文生成以下內容（JSON 格式）：

```json
{{
    "title_zh": "論文中文標題",
    "abstract_zh": "中文摘要翻譯（保持學術風格，約 200-300 字）",
    "relevance_score": 8,
    "relevance_explanation": "與凱文論文的關聯說明（1-2 段）",
    "reference_points": [
        "方法論：可參考的研究方法",
        "資料來源：可參考的資料集",
        "研究設計：可參考的設計"
    ],
    "research_design": "研究設計說明（實證/理論/案例等）",
    "data_sources": "使用的資料集、樣本規模、時間範圍",
    "analysis_methods": "使用的統計/計量方法",
    "main_findings": [
        "發現一：...",
        "發現二：...",
        "發現三：..."
    ]
}}
```

請確保 JSON 格式正確，可以被程式解析。"""


# ============================================================
# 資料庫查詢
# ============================================================

def get_high_priority_papers_without_notes(limit: int = 10) -> list:
    """
    取得尚未生成筆記的高優先級論文

    Args:
        limit: 最多取得幾篇

    Returns:
        論文列表
    """
    if not DATABASE_PATH.exists():
        logger.error("資料庫不存在")
        return []

    try:
        conn = sqlite3.connect(DATABASE_PATH)
        conn.row_factory = sqlite3.Row
        cursor = conn.cursor()

        # 查詢高優先級且尚未生成筆記的論文
        cursor.execute("""
            SELECT p.*
            FROM papers p
            WHERE p.priority = 'high'
            AND p.note_generated IS NULL OR p.note_generated = 0
            ORDER BY p.discovered_at DESC
            LIMIT ?
        """, (limit,))

        papers = [dict(row) for row in cursor.fetchall()]
        conn.close()
        return papers

    except Exception as e:
        logger.error(f"查詢論文失敗: {e}")
        return []


def get_paper_by_id(paper_id: int) -> Optional[dict]:
    """
    根據 ID 取得論文

    Args:
        paper_id: 論文 ID

    Returns:
        論文資料或 None
    """
    if not DATABASE_PATH.exists():
        return None

    try:
        conn = sqlite3.connect(DATABASE_PATH)
        conn.row_factory = sqlite3.Row
        cursor = conn.cursor()

        cursor.execute("SELECT * FROM papers WHERE id = ?", (paper_id,))
        row = cursor.fetchone()
        conn.close()

        if row:
            return dict(row)
        return None

    except Exception as e:
        logger.error(f"查詢論文失敗: {e}")
        return None


def mark_note_generated(paper_id: int, note_path: str) -> bool:
    """
    標記論文已生成筆記

    Args:
        paper_id: 論文 ID
        note_path: 筆記路徑

    Returns:
        是否成功
    """
    if not DATABASE_PATH.exists():
        return False

    try:
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()

        # 檢查欄位是否存在，不存在則新增
        cursor.execute("PRAGMA table_info(papers)")
        columns = [col[1] for col in cursor.fetchall()]

        if "note_generated" not in columns:
            cursor.execute("ALTER TABLE papers ADD COLUMN note_generated INTEGER DEFAULT 0")
        if "note_path" not in columns:
            cursor.execute("ALTER TABLE papers ADD COLUMN note_path TEXT")
        if "note_generated_at" not in columns:
            cursor.execute("ALTER TABLE papers ADD COLUMN note_generated_at TIMESTAMP")

        cursor.execute("""
            UPDATE papers
            SET note_generated = 1,
                note_path = ?,
                note_generated_at = CURRENT_TIMESTAMP
            WHERE id = ?
        """, (note_path, paper_id))

        conn.commit()
        conn.close()
        return True

    except Exception as e:
        logger.error(f"標記論文失敗: {e}")
        return False


# ============================================================
# LLM 分析
# ============================================================

def generate_note_content(paper: dict) -> dict:
    """
    使用 LLM 生成論文筆記內容

    Args:
        paper: 論文資料

    Returns:
        {
            "success": bool,
            "content": dict,  # 解析後的 JSON
            "error": str,
        }
    """
    result = {
        "success": False,
        "content": {},
        "error": "",
    }

    # 準備提示詞
    prompt = NOTE_GENERATION_PROMPT.format(
        title=paper.get("title", "N/A"),
        journal=paper.get("journal", "N/A"),
        authors=paper.get("authors", "N/A"),
        doi=paper.get("doi", "N/A"),
        publication_date=paper.get("publication_date", "N/A"),
        abstract=paper.get("abstract", "N/A"),
    )

    # 呼叫 LLM
    llm_result = call_claude_cli(prompt, timeout=180)

    if not llm_result["success"]:
        result["error"] = llm_result["error"]
        return result

    # 解析 JSON
    try:
        # 尋找 JSON 區塊
        json_match = re.search(r'```json\s*([\s\S]*?)\s*```', llm_result["content"])
        if json_match:
            json_str = json_match.group(1)
        else:
            # 嘗試直接解析整個回應
            json_str = llm_result["content"]

        result["content"] = json.loads(json_str)
        result["success"] = True

    except json.JSONDecodeError as e:
        result["error"] = f"JSON 解析失敗: {e}"
        # 儲存原始回應供除錯
        result["raw_response"] = llm_result["content"]

    return result


# ============================================================
# 筆記生成
# ============================================================

def sanitize_filename(title: str, max_length: int = 50) -> str:
    """
    清理檔名，移除特殊字元

    Args:
        title: 論文標題
        max_length: 最大長度

    Returns:
        安全的檔名
    """
    # 移除特殊字元
    safe_title = re.sub(r'[<>:"/\\|?*]', '', title)
    # 將空白替換為連字號
    safe_title = re.sub(r'\s+', '-', safe_title)
    # 移除連續連字號
    safe_title = re.sub(r'-+', '-', safe_title)
    # 截斷
    if len(safe_title) > max_length:
        safe_title = safe_title[:max_length].rstrip('-')
    return safe_title


def generate_stars(score: int) -> str:
    """生成星星評分"""
    full_stars = score // 2
    half_star = score % 2
    empty_stars = 5 - full_stars - half_star
    return "★" * full_stars + ("☆" if half_star else "") + "☆" * empty_stars


def get_journal_info(journal_name: str) -> dict:
    """取得期刊資訊"""
    for abbr, info in JOURNALS.items():
        if info["name"] == journal_name:
            return {"abbr": abbr, **info}
    return {"abbr": "", "name": journal_name, "tier": ""}


def format_authors_yaml(authors: str) -> str:
    """格式化作者為 YAML 列表"""
    if not authors:
        return '  - "Unknown"'

    # 分割作者（可能用逗號或分號分隔）
    author_list = re.split(r'[;,]', authors)
    lines = []
    for author in author_list[:5]:  # 最多取 5 位
        author = author.strip()
        if author:
            lines.append(f'  - "{author}"')
    return '\n'.join(lines) if lines else '  - "Unknown"'


def format_keywords_yaml(keywords: list) -> str:
    """格式化關鍵字為 YAML 列表"""
    if not keywords:
        return '  - "N/A"'
    lines = [f'  - "{kw}"' for kw in keywords[:5]]
    return '\n'.join(lines)


def create_paper_note(paper: dict, llm_content: dict) -> str:
    """
    建立論文筆記 Markdown 內容

    Args:
        paper: 論文資料
        llm_content: LLM 生成的內容

    Returns:
        Markdown 字串
    """
    today = datetime.now().strftime("%Y-%m-%d")
    journal_info = get_journal_info(paper.get("journal", ""))

    # 提取關鍵字
    keywords = paper.get("keywords", "").split(",") if paper.get("keywords") else []
    keywords = [k.strip() for k in keywords if k.strip()]

    # 相關性評分
    relevance_score = llm_content.get("relevance_score", 5)
    relevance_stars = generate_stars(relevance_score)

    # 主要發現格式化
    main_findings = llm_content.get("main_findings", [])
    if isinstance(main_findings, list):
        findings_text = "\n".join([f"{i+1}. **發現{i+1}**：{f}" for i, f in enumerate(main_findings)])
    else:
        findings_text = str(main_findings)

    # 可參考部分格式化
    reference_points = llm_content.get("reference_points", [])
    if isinstance(reference_points, list):
        ref_text = "\n".join([f"- {r}" for r in reference_points])
    else:
        ref_text = str(reference_points)

    # 生成 BibTeX
    first_author = paper.get("authors", "Unknown").split(",")[0].strip().split()[-1] if paper.get("authors") else "Unknown"
    year = paper.get("publication_date", "")[:4] if paper.get("publication_date") else "2026"
    bibtex = f"""@article{{{first_author.lower()}{year},
    title = {{{paper.get("title", "N/A")}}},
    author = {{{paper.get("authors", "N/A")}}},
    journal = {{{paper.get("journal", "N/A")}}},
    year = {{{year}}},
    doi = {{{paper.get("doi", "N/A")}}}
}}"""

    note = f"""---
# ===== 來源標記（重要） =====
source: "auto"
generated_by: "journal-paper-monitor"
generated_at: {today}

# ===== 論文基本資訊 =====
paper_id: {paper.get("id", 0)}
title: "{paper.get("title", "N/A")}"
title_zh: "{llm_content.get("title_zh", "")}"
journal: "{paper.get("journal", "N/A")}"
journal_abbr: "{journal_info.get("abbr", "")}"
tier: "{journal_info.get("tier", "")}"
doi: "{paper.get("doi", "N/A")}"
publication_date: {paper.get("publication_date", "N/A")}

# ===== 作者資訊 =====
authors:
{format_authors_yaml(paper.get("authors", ""))}

# ===== 分類與優先級 =====
priority: "{paper.get("priority", "high")}"
domain:
  - "不動產"
keywords:
{format_keywords_yaml(keywords)}

# ===== 閱讀追蹤 =====
read: false
read_date:

# ===== 與凱文論文關聯 =====
relevance_score: {relevance_score}
relevance_note: "{llm_content.get("relevance_explanation", "")[:100]}..."
---

# {paper.get("title", "N/A")}

> **期刊**: {paper.get("journal", "N/A")} ({journal_info.get("abbr", "")}) | {journal_info.get("tier", "")}
> **發表**: {paper.get("publication_date", "N/A")}
> **DOI**: {paper.get("doi", "N/A")}
> **自動生成**：本筆記由 journal-paper-monitor 自動生成，內容待驗證

---

## 摘要

### 英文原文

{paper.get("abstract", "N/A")}

### 中文翻譯

{llm_content.get("abstract_zh", "（翻譯生成失敗）")}

---

## 與凱文論文的關聯

**相關程度**: {relevance_stars} ({relevance_score}/10)

**關聯說明**:
{llm_content.get("relevance_explanation", "（分析生成失敗）")}

**可參考的部分**:
{ref_text}

---

## 方法論摘要

### 研究設計

{llm_content.get("research_design", "（分析生成失敗）")}

### 資料來源

{llm_content.get("data_sources", "（分析生成失敗）")}

### 分析方法

{llm_content.get("analysis_methods", "（分析生成失敗）")}

---

## 主要發現

{findings_text}

---

## 引用資訊

```bibtex
{bibtex}
```

---

## 個人筆記

<!-- 凱文閱讀後的個人筆記（手動填寫） -->


"""
    return note


def save_paper_note(paper: dict, note_content: str) -> Optional[str]:
    """
    儲存論文筆記

    Args:
        paper: 論文資料
        note_content: Markdown 內容

    Returns:
        儲存路徑或 None
    """
    today = datetime.now()
    year = today.strftime("%Y")
    month = today.strftime("%m")
    date_str = today.strftime("%Y-%m-%d")

    # 建立目錄
    note_dir = PAPERS_DIR / year / month
    note_dir.mkdir(parents=True, exist_ok=True)

    # 生成檔名
    safe_title = sanitize_filename(paper.get("title", "Untitled"))
    filename = f"{date_str}-{safe_title}.md"
    note_path = note_dir / filename

    try:
        note_path.write_text(note_content, encoding="utf-8")
        logger.info(f"筆記已儲存: {note_path}")
        return str(note_path.relative_to(RESEARCH_ZOO_ROOT))
    except Exception as e:
        logger.error(f"儲存筆記失敗: {e}")
        return None


# ============================================================
# 主要流程
# ============================================================

def generate_paper_note(paper_id: int) -> dict:
    """
    為單篇論文生成筆記

    Args:
        paper_id: 論文 ID

    Returns:
        {
            "success": bool,
            "note_path": str,
            "error": str,
        }
    """
    result = {
        "success": False,
        "note_path": "",
        "error": "",
    }

    # 取得論文
    paper = get_paper_by_id(paper_id)
    if not paper:
        result["error"] = f"找不到論文 ID: {paper_id}"
        return result

    logger.info(f"生成筆記: {paper.get('title', 'N/A')[:50]}...")

    # LLM 分析
    llm_result = generate_note_content(paper)
    if not llm_result["success"]:
        result["error"] = llm_result["error"]
        return result

    # 建立筆記內容
    note_content = create_paper_note(paper, llm_result["content"])

    # 儲存筆記
    note_path = save_paper_note(paper, note_content)
    if not note_path:
        result["error"] = "儲存筆記失敗"
        return result

    # 標記已生成
    mark_note_generated(paper_id, note_path)

    result["success"] = True
    result["note_path"] = note_path
    return result


def generate_all_pending_notes(limit: int = 5) -> dict:
    """
    為所有待處理的高優先級論文生成筆記

    Args:
        limit: 最多處理幾篇

    Returns:
        {
            "total": int,
            "success": int,
            "failed": int,
            "notes": list,
        }
    """
    papers = get_high_priority_papers_without_notes(limit)

    if not papers:
        logger.info("沒有待處理的論文")
        return {"total": 0, "success": 0, "failed": 0, "notes": []}

    logger.info(f"找到 {len(papers)} 篇待處理論文")

    notes = []
    success_count = 0
    failed_count = 0

    for paper in papers:
        result = generate_paper_note(paper["id"])

        if result["success"]:
            success_count += 1
            notes.append({
                "paper_id": paper["id"],
                "title": paper.get("title", "N/A"),
                "note_path": result["note_path"],
            })
        else:
            failed_count += 1
            logger.error(f"生成失敗: {paper.get('title', 'N/A')[:50]} - {result['error']}")

    return {
        "total": len(papers),
        "success": success_count,
        "failed": failed_count,
        "notes": notes,
    }


def get_generation_stats() -> dict:
    """
    取得筆記生成統計

    Returns:
        統計資料
    """
    if not DATABASE_PATH.exists():
        return {"error": "資料庫不存在"}

    try:
        conn = sqlite3.connect(DATABASE_PATH)
        cursor = conn.cursor()

        # 高優先級論文總數
        cursor.execute("SELECT COUNT(*) FROM papers WHERE priority = 'high'")
        total_high = cursor.fetchone()[0]

        # 已生成筆記數
        cursor.execute("SELECT COUNT(*) FROM papers WHERE note_generated = 1")
        generated = cursor.fetchone()[0]

        # 待生成數
        cursor.execute("""
            SELECT COUNT(*) FROM papers
            WHERE priority = 'high'
            AND (note_generated IS NULL OR note_generated = 0)
        """)
        pending = cursor.fetchone()[0]

        conn.close()

        return {
            "total_high_priority": total_high,
            "notes_generated": generated,
            "pending": pending,
        }

    except Exception as e:
        return {"error": str(e)}


# ============================================================
# CLI
# ============================================================

def main():
    import argparse

    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s - %(message)s",
    )

    parser = argparse.ArgumentParser(description="論文筆記自動生成工具（Phase 11）")
    parser.add_argument("--stats", action="store_true", help="查看生成統計")
    parser.add_argument("--generate", type=int, metavar="ID", help="為指定 ID 的論文生成筆記")
    parser.add_argument("--all", action="store_true", help="為所有待處理論文生成筆記")
    parser.add_argument("--limit", type=int, default=5, help="最多處理幾篇（預設 5）")
    parser.add_argument("--dry-run", action="store_true", help="模擬執行，不實際生成")
    args = parser.parse_args()

    if args.stats:
        stats = get_generation_stats()
        print("\n論文筆記生成統計")
        print("=" * 40)
        if "error" in stats:
            print(f"錯誤: {stats['error']}")
        else:
            print(f"高優先級論文總數: {stats['total_high_priority']}")
            print(f"已生成筆記:       {stats['notes_generated']}")
            print(f"待生成:           {stats['pending']}")
        return

    if args.generate:
        if args.dry_run:
            paper = get_paper_by_id(args.generate)
            if paper:
                print(f"[模擬] 將為以下論文生成筆記:")
                print(f"  標題: {paper.get('title', 'N/A')}")
                print(f"  期刊: {paper.get('journal', 'N/A')}")
            else:
                print(f"找不到論文 ID: {args.generate}")
            return

        result = generate_paper_note(args.generate)
        if result["success"]:
            print(f"筆記已生成: {result['note_path']}")
        else:
            print(f"生成失敗: {result['error']}")
        return

    if args.all:
        if args.dry_run:
            papers = get_high_priority_papers_without_notes(args.limit)
            print(f"[模擬] 將為 {len(papers)} 篇論文生成筆記:")
            for p in papers:
                print(f"  - {p.get('title', 'N/A')[:60]}")
            return

        result = generate_all_pending_notes(args.limit)
        print(f"\n生成完成")
        print(f"  處理: {result['total']} 篇")
        print(f"  成功: {result['success']} 篇")
        print(f"  失敗: {result['failed']} 篇")

        if result['notes']:
            print(f"\n已生成的筆記:")
            for note in result['notes']:
                print(f"  - {note['note_path']}")
        return

    print("用法:")
    print("  --stats            查看生成統計")
    print("  --generate ID      為指定 ID 的論文生成筆記")
    print("  --all              為所有待處理論文生成筆記")
    print("  --limit N          最多處理 N 篇（預設 5）")
    print("  --dry-run          模擬執行")


if __name__ == "__main__":
    main()
