#!/usr/bin/env python3
# 中文注释：
# 文件：echobot/skills/siyuan/scripts/tools.py
# 说明：SiYuan 业务工具封装，提供搜索、文档操作、SQL 查询等高层方法。
"""
SiYuan Skill Tools
"""

import re
from datetime import date
from typing import Optional

try:
    from .client import SiYuanClient
except ImportError:  # pragma: no cover - allow direct script execution
    from client import SiYuanClient


class SiYuanTools:
    """SiYuan Tools for Clawdbot"""

    DATE_PATTERN = re.compile(r"(20\d{2}-\d{2}-\d{2})")
    
    def __init__(self, client: Optional[SiYuanClient] = None):
        self.client = client or SiYuanClient()

    @staticmethod
    def _title_from_row(row: dict) -> str:
        hpath = str(row.get("hpath") or "").strip()
        if hpath:
            parts = [part for part in hpath.split("/") if part]
            if parts:
                return parts[-1]

        content = str(row.get("content") or "").replace("\n", " ").strip()
        if content:
            return content[:60]
        return "Untitled"

    @classmethod
    def _extract_date(cls, row: dict) -> Optional[date]:
        source = f"{row.get('hpath', '')} {row.get('content', '')}"
        match = cls.DATE_PATTERN.search(source)
        if not match:
            return None
        try:
            return date.fromisoformat(match.group(1))
        except ValueError:
            return None
    
    def search_notes(self, query: str, limit: int = 20, type: str = "blocks") -> str:
        """Search for notes or blocks"""
        try:
            result = self.client.search(query, limit, type)
            if result.get("code") != 0:
                return f"❌ Search failed: {result.get('msg') or 'unknown error'}"

            rows = result.get("data") or []
            if not isinstance(rows, list):
                return "❌ Search failed: unexpected response format"

            if not rows:
                return f"🔍 No results found for '{query}'"
            
            output = [f"🔍 Search results for '{query}' ({len(rows)}):\n"]
            
            for i, row in enumerate(rows[:10], 1):
                block_type = row.get("type", "")
                content = str(row.get("content") or "").replace("\n", " ")[:100]
                hpath = str(row.get("hpath") or "")
                suffix = f" ({hpath})" if hpath else ""
                output.append(f"{i}. [{block_type}] {content}{suffix}")
            
            if len(rows) > 10:
                output.append(f"\n... and {len(rows) - 10} more")
            
            return "\n".join(output)
        except Exception as e:
            return f"❌ Search failed: {e}"
    
    def get_notebooks(self) -> str:
        """Get all notebooks"""
        try:
            result = self.client.get_notebooks()
            if result.get("code") != 0:
                return f"❌ Failed: {result.get('msg') or 'unknown error'}"

            notebooks = (result.get("data") or {}).get("notebooks", [])
            
            if not notebooks:
                return "📚 No notebooks found"
            
            output = ["📚 Notebooks:\n"]
            for nb in notebooks:
                name = nb.get("name", "Untitled")
                notebook_id = nb.get("id", "")
                status = "closed" if nb.get("closed") else "open"
                output.append(f"• {name} ({notebook_id}) [{status}]")
            
            return "\n".join(output)
        except Exception as e:
            return f"❌ Failed: {e}"
    
    def get_recent_docs(self, limit: int = 10) -> str:
        """Get recent documents"""
        try:
            result = self.client.get_recent_docs(limit)
            if result.get("code") != 0:
                return f"❌ Failed: {result.get('msg') or 'unknown error'}"

            docs = result.get("data") or []
            if not isinstance(docs, list):
                return "❌ Failed: unexpected response format"
            
            if not docs:
                return "📄 No recent documents"
            
            output = ["📄 Recent Documents:\n"]
            for doc in docs[:10]:
                title = self._title_from_row(doc)
                hpath = str(doc.get("hpath") or "")
                output.append(f"• {title} ({hpath or 'no-path'})")
            
            return "\n".join(output)
        except Exception as e:
            return f"❌ Failed: {e}"
    
    def get_daily_notes(self, start_date: str, end_date: str) -> str:
        """Get daily notes by date range"""
        try:
            start = date.fromisoformat(start_date)
            end = date.fromisoformat(end_date)
            if start > end:
                return "❌ Failed: start_date must be <= end_date"

            result = self.client.get_dailies(start_date, end_date)
            if result.get("code") != 0:
                return f"❌ Failed: {result.get('msg') or 'unknown error'}"

            docs = result.get("data") or []
            if not isinstance(docs, list):
                return "❌ Failed: unexpected response format"

            matched = []
            for doc in docs:
                doc_date = self._extract_date(doc)
                if doc_date and start <= doc_date <= end:
                    matched.append((doc_date, doc))
            
            if not matched:
                return f"📅 No daily notes from {start_date} to {end_date}"
            
            matched.sort(key=lambda item: item[0], reverse=True)
            output = [f"📅 Daily Notes ({start_date} to {end_date}) [{len(matched)}]:\n"]
            for doc_date, doc in matched[:50]:
                title = self._title_from_row(doc)
                output.append(f"• {doc_date.isoformat()} - {title}")
            
            return "\n".join(output)
        except ValueError:
            return "❌ Failed: start_date/end_date must be YYYY-MM-DD"
        except Exception as e:
            return f"❌ Failed: {e}"
    
    def get_document(self, doc_id: str) -> str:
        """Get document content"""
        try:
            result = self.client.get_document(doc_id)
            if result.get("code") != 0:
                return f"❌ Failed: {result.get('msg') or 'unknown error'}"

            data = result.get("data") or {}
            content = str(data.get("content") or "")
            hpath = str(data.get("hPath") or "")
            title = hpath.split("/")[-1] if hpath else doc_id
            
            return f"📄 {title}\n路径: {hpath or '-'}\n\n{content[:2000]}"
        except Exception as e:
            return f"❌ Failed: {e}"
    
    def create_document(self, notebook_id: str, path: str, title: str, content: str = "") -> str:
        """Create a new document"""
        try:
            result = self.client.create_doc(notebook_id, path, title, content)
            if result.get("code") == 0:
                doc_id = result.get("data")
                return f"✅ Document created: {title} ({doc_id})"
            return f"❌ Failed: {result.get('msg') or 'unknown error'}"
        except Exception as e:
            return f"❌ Failed: {e}"
    
    def update_document(self, doc_id: str, content: str) -> str:
        """Update document content"""
        try:
            result = self.client.update_doc(doc_id, content)
            if result.get("code") == 0:
                return f"✅ Document updated"
            return f"❌ Failed: {result.get('msg') or 'unknown error'}"
        except Exception as e:
            return f"❌ Failed: {e}"
    
    def query_database(self, sql: str) -> str:
        """Execute SQL query"""
        try:
            result = self.client.query_sql(sql)
            if result.get("code") != 0:
                return f"❌ Query failed: {result.get('msg') or 'unknown error'}"

            data = result.get("data")
            
            if data is None or data == []:
                return "📊 No results"
            
            if isinstance(data, list) and len(data) > 0:
                first = data[0]
                if not isinstance(first, dict):
                    return f"📊 Query Results ({len(data)} rows):\n{data[:5]}"

                keys = list(first.keys())
                output = [f"📊 Query Results ({len(data)} rows):\n"]
                output.append(" | ".join(keys[:3]))
                output.append("-" * 30)
                
                for row in data[:5]:
                    if not isinstance(row, dict):
                        output.append(str(row)[:80])
                        continue
                    values = [str(row.get(k, ""))[:20] for k in keys[:3]]
                    output.append(" | ".join(values))
                
                if len(data) > 5:
                    output.append(f"... and {len(data) - 5} more rows")
                
                return "\n".join(output)

            if isinstance(data, dict):
                return f"📊 Query Result:\n{data}"
            return str(data)
        except Exception as e:
            return f"❌ Query failed: {e}"
    
    def query_blocks_hsql(self, hsql: str, limit: int = 100) -> str:
        """Query blocks using HSQL"""
        try:
            result = self.client.query_blocks(hsql, limit)
            if result.get("code") != 0:
                return f"❌ Query failed: {result.get('msg') or 'unknown error'}"

            blocks = result.get("data") or []
            if not isinstance(blocks, list):
                return f"🔍 Query Result:\n{blocks}"
            
            if not blocks:
                return "🔍 No blocks found"
            
            output = [f"🔍 Query Results ({len(blocks)} blocks):\n"]
            for block in blocks[:10]:
                if isinstance(block, dict):
                    content = str(block.get("content") or "").replace("\n", " ")[:80]
                    block_type = block.get("type", "")
                else:
                    content = str(block)[:80]
                    block_type = ""
                output.append(f"• [{block_type}] {content}")
            
            return "\n".join(output)
        except Exception as e:
            return f"❌ Query failed: {e}"
