"""
国自然基金搜索任务
"""

import json
from typing import Optional, List
from pathlib import Path

from .models import ProjectInfo, SearchResults
from ..memory import get_memory


class NSFCSearchTask:
    """国自然基金搜索任务"""
    
    NSFC_URL = "https://kd.nsfc.cn/"
    WEBSITE_KEY = "kd.nsfc.cn"
    
    def __init__(self, agent, memory_dir: str = "./memory"):
        """
        初始化搜索任务
        
        Args:
            agent: NSFCAgent 实例
            memory_dir: 记忆存储目录
        """
        self.agent = agent
        self.memory = get_memory(memory_dir)
    
    def _get_experience_context(self, task_type: str = "搜索") -> str:
        """获取相关经验作为上下文"""
        return self.memory.get_all_for_context(
            website=self.WEBSITE_KEY,
            task_type=task_type
        )
    
    def _record_success(self, task_type: str, keyword: str, count: int, details: str = ""):
        """记录成功经验"""
        exp = f"搜索'{keyword}'成功获取{count}条结果"
        if details:
            exp += f"，{details}"
        self.memory.add_task_experience(task_type, exp)
        print(f"📝 经验已记录: {exp[:50]}...")
    
    def _record_failure(self, task_type: str, error: str, context: str = ""):
        """记录失败教训"""
        exp = f"失败原因: {error}"
        if context:
            exp += f"。发生场景: {context}"
        self.memory.add_task_experience(task_type, exp)
        self.memory.add_website_experience(self.WEBSITE_KEY, exp, "注意事项")
        print(f"📝 教训已记录: {exp[:50]}...")
    
    def _build_search_task(
        self,
        keyword: str,
        pages: int = 1,
        include_abstract: bool = False,
    ) -> str:
        """构建搜索任务描述 - 强制要求完成所有步骤"""
        
        # 根据是否需要摘要决定任务复杂度
        abstract_instruction = ""
        if include_abstract:
            abstract_instruction = """
**第四步：获取详情页信息（必须执行！）**
对于提取到的每个项目，必须：
1. 点击项目标题链接，进入详情页
2. 从详情页提取：中文摘要(abstract_cn)、结题摘要(conclusion_abstract)
3. 记录详情页URL (detail_url)
4. 返回列表页，继续下一个项目
5. 重复直到所有项目都获取了详情

⚠️ 警告：如果没有获取详情页信息，任务视为失败！
"""
        
        task = f"""
## 任务：搜索国自然项目并提取完整数据

### ⚠️ 强制要求（必须全部完成，否则任务失败）
1. 必须提取 {pages} 页数据（每页10条，共 {pages * 10} 条）
2. 必须提取每个项目的所有字段
3. {"必须点击进入详情页获取摘要信息" if include_abstract else "列表页信息即可"}
4. 不允许只提取第1页就结束

### 第一步：搜索
1. 打开 {self.NSFC_URL}
2. 在搜索框输入：{keyword}
3. 等待下拉菜单出现，点击"按结题项目"按钮
4. 等待搜索结果页加载完成

### 第二步：提取当前页数据
从每个项目卡片提取：
- project_name: 项目名称
- project_leader: 负责人
- institution: 依托单位  
- approval_no: 批准号
- apply_code: 申请代码
- project_type: 项目类别
- funding_amount: 资助经费
- approval_year: 批准年度
- end_year: 结题年度
- keywords: 关键词

### 第三步：翻页提取（共 {pages} 页）
- 当前页提取完成后，点击下一页
- 重复第二步，直到提取完 {pages} 页
- 页面底部有分页控件，点击页码数字翻页
{abstract_instruction}
### 输出格式
```json
{{
  "keyword": "{keyword}",
  "total_count": 总数,
  "projects": [
    {{
      "project_name": "...",
      "project_leader": "...",
      "institution": "...",
      "approval_no": "...",
      "apply_code": "...",
      "project_type": "...",
      "funding_amount": "...",
      "approval_year": "...",
      "end_year": "...",
      "keywords": "..."
    }}
  ]
}}
```

### 完成标准
- ✅ 提取了 {pages} 页数据
- ✅ 每个项目都有完整字段
- {"✅ 每个项目都有详情页摘要" if include_abstract else ""}
"""
        # 注入经验上下文
        experience_context = self._get_experience_context("搜索")
        if experience_context:
            task += f"\n\n### 历史经验（请务必参考）\n{experience_context}"
        
        return task.strip()
    
    async def search(
        self,
        keyword: str,
        pages: int = 1,
        include_abstract: bool = False,
    ) -> SearchResults:
        """
        执行搜索任务（带自动学习）
        """
        task = self._build_search_task(keyword, pages, include_abstract)
        
        try:
            result = await self.agent.run(task, output_model=SearchResults)
            
            # 解析结果
            search_results = None
            if result.get("parsed"):
                search_results = SearchResults(**result["parsed"])
            else:
                raw = result.get("raw_result", "")
                if raw:
                    try:
                        data = json.loads(raw)
                        search_results = SearchResults(keyword=keyword, **data)
                    except json.JSONDecodeError:
                        pass
            
            # 记录经验
            if search_results and search_results.projects:
                self._record_success(
                    "搜索", keyword, len(search_results.projects),
                    f"共{pages}页，步骤数:{result.get('steps_taken', '未知')}"
                )
                return search_results
            else:
                # 搜索完成但无结果
                self._record_failure(
                    "搜索", 
                    "搜索完成但未获取到项目数据",
                    f"关键词'{keyword}'，原始结果长度:{len(result.get('raw_result', ''))}"
                )
                return SearchResults(keyword=keyword, projects=[])
                
        except Exception as e:
            # 记录失败
            self._record_failure(
                "搜索",
                str(e),
                f"关键词'{keyword}'，页数{pages}"
            )
            raise
    
    def _build_detail_task(self, detail_url: str) -> str:
        """构建详情页爬取任务"""
        task = f"""
## 任务：提取国自然项目详情页的完整信息

### 目标页面
{detail_url}

### 页面结构
详情页包含以下区块（从上到下）：

1. **基本信息**
   - 项目批准号、申请代码、项目名称
   - 项目负责人、依托单位
   - 研究期限（格式：2021-01-01 至 2024-12-31）
   - 资助经费（万元）

2. **项目参与人**
   - 每人包含：姓名、职称、单位
   - 可能有"查看全部"按钮

3. **项目摘要**
   - 中文摘要：详细的项目描述
   - 英文摘要：Abstract

4. **结题摘要**
   - 项目完成后的总结

5. **成果统计**
   - 期刊论文数量、专利数量等

6. **成果产出**
   - 论文/专利列表，每条包含：标题、类型、作者

### 输出格式
```json
{{
  "project_name": "项目名称",
  "approval_no": "批准号",
  "apply_code": "申请代码",
  "project_leader": "负责人",
  "institution": "依托单位",
  "research_period": "研究期限",
  "funding_amount": "资助经费",
  "abstract_cn": "中文摘要全文",
  "abstract_en": "英文摘要全文",
  "conclusion_abstract": "结题摘要全文",
  "participants": [
    {{"name": "姓名", "title": "职称", "institution": "单位"}}
  ],
  "paper_count": 期刊论文数量,
  "patent_count": 专利数量,
  "publications": [
    {{"title": "成果标题", "pub_type": "类型", "authors": "作者"}}
  ]
}}
```

### 注意事项
1. 摘要内容要完整提取，不要截断
2. 如果某个字段显示"暂无"，则设为 null
3. 成果产出列表可能很长，全部提取
"""
        # 注入经验上下文
        experience_context = self._get_experience_context("详情提取")
        if experience_context:
            task += f"\n\n### 历史经验（请务必参考）\n{experience_context}"
        
        return task.strip()
    
    async def get_detail(self, detail_url: str) -> ProjectInfo:
        """获取项目详情页完整信息（带自动学习）"""
        task = self._build_detail_task(detail_url)
        
        try:
            result = await self.agent.run(task, output_model=ProjectInfo)
            
            if result.get("parsed"):
                info = ProjectInfo(**result["parsed"])
                # 成功获取详情
                if info.project_name:
                    self._record_success(
                        "详情提取", info.project_name[:20],
                        1, f"成功提取摘要和成果信息"
                    )
                return info
            
            # 未能解析
            self._record_failure(
                "详情提取",
                "无法解析详情页数据",
                f"URL: {detail_url[:50]}"
            )
            return ProjectInfo(
                project_name="",
                project_leader="",
                institution=""
            )
            
        except Exception as e:
            self._record_failure(
                "详情提取",
                str(e),
                f"URL: {detail_url[:50]}"
            )
            raise
    
    def save_results(
        self,
        results: SearchResults,
        output_path: str,
        format: str = "json",
    ) -> str:
        """
        保存搜索结果
        
        Args:
            results: 搜索结果
            output_path: 输出路径
            format: 输出格式 (json, csv, markdown)
            
        Returns:
            保存的文件路径
        """
        path = Path(output_path)
        path.parent.mkdir(parents=True, exist_ok=True)
        
        if format == "json":
            return self._save_json(results, path)
        elif format == "csv":
            return self._save_csv(results, path)
        elif format == "markdown":
            return self._save_markdown(results, path)
        else:
            raise ValueError(f"不支持的格式: {format}")
    
    def _save_json(self, results: SearchResults, path: Path) -> str:
        """保存为 JSON"""
        file_path = path.with_suffix(".json")
        with open(file_path, "w", encoding="utf-8") as f:
            json.dump(results.model_dump(), f, ensure_ascii=False, indent=2)
        return str(file_path)
    
    def _save_csv(self, results: SearchResults, path: Path) -> str:
        """保存为 CSV"""
        import csv
        file_path = path.with_suffix(".csv")
        
        if not results.projects:
            return str(file_path)
        
        fieldnames = list(results.projects[0].model_dump().keys())
        with open(file_path, "w", encoding="utf-8-sig", newline="") as f:
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            for project in results.projects:
                writer.writerow(project.model_dump())
        
        return str(file_path)
    
    def _save_markdown(self, results: SearchResults, path: Path) -> str:
        """保存为 Markdown"""
        file_path = path.with_suffix(".md")
        
        lines = [
            f"# 国自然基金搜索结果",
            f"",
            f"**关键词**: {results.keyword}",
            f"**结果数**: {results.total_count or len(results.projects)}",
            f"",
            "## 项目列表",
            "",
        ]
        
        for i, p in enumerate(results.projects, 1):
            lines.extend([
                f"### {i}. {p.project_name}",
                f"- **负责人**: {p.project_leader}",
                f"- **依托单位**: {p.institution}",
                f"- **金额**: {p.funding_amount or '未知'}万元",
                f"- **批准年份**: {p.approval_year or '未知'}",
                f"- **项目类型**: {p.project_type or '未知'}",
                "",
            ])
        
        with open(file_path, "w", encoding="utf-8") as f:
            f.write("\n".join(lines))
        
        return str(file_path)

    async def search_with_filters(
        self,
        keyword: str,
        year_start: Optional[int] = None,
        year_end: Optional[int] = None,
        project_type: Optional[str] = None,
        pages: int = 1,
    ) -> SearchResults:
        """
        带筛选条件的搜索
        
        Args:
            keyword: 搜索关键词
            year_start: 起始年份
            year_end: 结束年份
            project_type: 项目类型
            pages: 爬取页数
        """
        filters = []
        if year_start and year_end:
            filters.append(f"筛选年份范围: {year_start}-{year_end}")
        elif year_start:
            filters.append(f"筛选年份: {year_start}年及以后")
        
        if project_type:
            filters.append(f"筛选项目类型: {project_type}")
        
        filter_instruction = ""
        if filters:
            filter_instruction = "\n        6. " + "\n        7. ".join(filters)
        
        task = self._build_search_task(keyword, pages) + filter_instruction
        result = await self.agent.run(task, output_model=SearchResults)
        
        if result.get("parsed"):
            return SearchResults(**result["parsed"])
        
        return SearchResults(keyword=keyword, projects=[])
