"""Document store for GreyMatter.

Stores all knowledge artifacts -- session logs, design docs, research outputs,
summaries. Source of truth for project knowledge. Git-tracked files are
rendered exports from this store.
"""
from pathlib import Path
from typing import Any

from .db import Database
from .ids import generate_document_id

DOC_TYPES = {"session_log", "design", "plan", "research", "summary", "decision", "export"}


def _estimate_tokens(text: str) -> int:
    """Rough token estimate: ~4 chars per token for English text."""
    return max(1, len(text) // 4)


class DocumentStore:
    """CRUD and retrieval for knowledge documents."""

    def __init__(self, db: Database) -> None:
        self.db = db

    def create(
        self,
        doc_type: str,
        title: str,
        content: str,
        format: str = "markdown",
        tags: str | None = None,
        project: str | None = None,
        parent_id: str | None = None,
        summary: str | None = None,
    ) -> dict[str, Any]:
        """Create a new document and return it."""
        doc_id = generate_document_id()
        token_estimate = _estimate_tokens(content)
        self.db.execute(
            """INSERT INTO documents
               (id, doc_type, title, content, format, tags, project,
                parent_id, summary, token_estimate)
               VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
            (doc_id, doc_type, title, content, format, tags, project,
             parent_id, summary, token_estimate),
        )
        return self.get(doc_id)

    def get(self, doc_id: str) -> dict[str, Any] | None:
        """Retrieve a document by ID."""
        return self.db.execute_one("SELECT * FROM documents WHERE id = ?", (doc_id,))

    def search(
        self,
        doc_type: str | None = None,
        project: str | None = None,
        tags: str | None = None,
        since: str | None = None,
        limit: int = 20,
    ) -> list[dict[str, Any]]:
        """Search documents with optional filters."""
        query = "SELECT * FROM documents WHERE 1=1"
        params: list = []

        if doc_type:
            query += " AND doc_type = ?"
            params.append(doc_type)
        if project:
            query += " AND project = ?"
            params.append(project)
        if tags:
            escaped_tags = tags.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
            query += " AND tags LIKE ? ESCAPE '\\'"
            params.append(f"%{escaped_tags}%")
        if since:
            query += " AND created_at >= ?"
            params.append(since)

        query += " ORDER BY updated_at DESC LIMIT ?"
        params.append(limit)
        return self.db.execute(query, tuple(params))

    def search_summary(
        self,
        doc_type: str | None = None,
        project: str | None = None,
        tags: str | None = None,
        since: str | None = None,
        limit: int = 20,
    ) -> dict[str, Any]:
        """Search documents returning compact summaries without full content."""
        where = "WHERE 1=1"
        params: list = []
        if doc_type:
            where += " AND doc_type = ?"
            params.append(doc_type)
        if project:
            where += " AND project = ?"
            params.append(project)
        if tags:
            escaped_tags = tags.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")
            where += " AND tags LIKE ? ESCAPE '\\'"
            params.append(f"%{escaped_tags}%")
        if since:
            where += " AND created_at >= ?"
            params.append(since)

        count_row = self.db.execute_one(
            f"SELECT COUNT(*) as total FROM documents {where}", tuple(params)
        )
        total = count_row["total"] if count_row else 0
        results = self.db.execute(
            f"""SELECT id, doc_type, title, substr(content, 1, 200) as content_preview,
                       project, tags, token_estimate, created_at
                FROM documents {where}
                ORDER BY updated_at DESC LIMIT ?""",
            tuple(params + [limit]),
        )
        return {"total": total, "returned": len(results), "documents": results}

    def get_context(
        self, project: str | None = None, max_tokens: int = 4000
    ) -> list[dict[str, Any]]:
        """Smart context retrieval -- serves summaries for large/old docs,
        full content for small/recent docs. Stays within token budget."""
        docs = self.search(project=project, limit=50)
        result: list[dict[str, Any]] = []
        tokens_used = 0

        for doc in docs:
            est = doc.get("token_estimate", 0) or 0
            if tokens_used + est <= max_tokens:
                result.append(doc)
                tokens_used += est
            elif doc.get("summary") and tokens_used + _estimate_tokens(doc["summary"]) <= max_tokens:
                summary_doc = dict(doc)
                summary_doc["content"] = doc["summary"]
                summary_doc["token_estimate"] = _estimate_tokens(doc["summary"])
                result.append(summary_doc)
                tokens_used += summary_doc["token_estimate"]
            else:
                continue

        return result

    def summarize(self, doc_id: str, summary_text: str) -> None:
        """Attach or update a summary for a document."""
        self.db.execute(
            "UPDATE documents SET summary = ?, updated_at = datetime('now') WHERE id = ?",
            (summary_text, doc_id),
        )

    def import_file(
        self,
        file_path: str,
        doc_type: str,
        project: str | None = None,
        tags: str | None = None,
    ) -> dict[str, Any]:
        """Import an existing markdown file into the documents table."""
        path = Path(file_path)
        content = path.read_text()
        title = path.stem
        return self.create(
            doc_type=doc_type,
            title=title,
            content=content,
            project=project,
            tags=tags,
        )


    def count(self, doc_type: str | None = None, project: str | None = None) -> int:
        """Count documents, optionally filtered."""
        where = "WHERE 1=1"
        params: list = []
        if doc_type:
            where += " AND doc_type = ?"
            params.append(doc_type)
        if project:
            where += " AND project = ?"
            params.append(project)
        row = self.db.execute_one(
            f"SELECT COUNT(*) as total FROM documents {where}", tuple(params)
        )
        return row["total"] if row else 0

    def export_markdown(self, doc_id: str) -> str:
        """Render a document as markdown for git-tracked export."""
        doc = self.get(doc_id)
        if doc is None:
            return ""
        lines = [
            f"# {doc['title']}",
            "",
            f"**Type:** {doc['doc_type']}  ",
            f"**Project:** {doc.get('project', 'N/A')}  ",
            f"**Created:** {doc['created_at']}  ",
            f"**Tags:** {doc.get('tags', 'none')}  ",
            "",
            "---",
            "",
            doc["content"],
        ]
        return "\n".join(lines)
