"""Knowledge graph export/import for GreyMatter Solo.

Supports JSON (lossless round-trip) and Markdown (human-readable) formats.
Selective export by domain, entry type, or date range.
Import with duplicate detection to prevent re-ingestion.

Usage:
    exporter = KnowledgeExporter(db)
    data = exporter.to_json(domain="python")
    exporter.to_json_file("export.json")
    exporter.to_markdown_file("export.md")

    importer = KnowledgeImporter(db)
    result = importer.from_json(data)
    result = importer.from_json_file("export.json")
"""
from __future__ import annotations

import json
from datetime import datetime
from typing import Any

from .db import Database
from .ids import generate_knowledge_id


_EXPORT_FIELDS = [
    "id", "entry_type", "title", "content", "domain", "scope",
    "tags", "valence", "created_at", "updated_at",
]

_OBSERVATION_FIELDS = [
    "id", "category", "title", "content", "confidence",
    "stability_days", "last_confirmed_at", "created_at",
]


class KnowledgeExporter:
    """Export knowledge entries and observations."""

    def __init__(self, db: Database):
        self.db = db

    def to_json(
        self,
        domain: str | None = None,
        entry_type: str | None = None,
        since: str | None = None,
        include_observations: bool = True,
    ) -> dict[str, Any]:
        """Export to a JSON-serializable dict.

        Args:
            domain: Filter to a specific domain.
            entry_type: Filter to a specific entry type.
            since: ISO date string — only entries created/updated after this.
            include_observations: Also export observations.
        """
        entries = self._query_entries(domain, entry_type, since)
        result: dict[str, Any] = {
            "format": "greymatter-export",
            "version": "1.0",
            "exported_at": datetime.now().isoformat(),
            "filters": {
                "domain": domain,
                "entry_type": entry_type,
                "since": since,
            },
            "knowledge_entries": [
                {k: e.get(k) for k in _EXPORT_FIELDS}
                for e in entries
            ],
        }

        if include_observations:
            observations = self._query_observations(since)
            result["observations"] = [
                {k: o.get(k) for k in _OBSERVATION_FIELDS}
                for o in observations
            ]

        result["counts"] = {
            "knowledge_entries": len(result["knowledge_entries"]),
            "observations": len(result.get("observations", [])),
        }
        return result

    def to_json_file(self, path: str, **kwargs) -> dict[str, int]:
        """Export to a JSON file. Returns counts."""
        data = self.to_json(**kwargs)
        with open(path, "w") as f:
            json.dump(data, f, indent=2, default=str)
        return data["counts"]

    def to_markdown(
        self,
        domain: str | None = None,
        entry_type: str | None = None,
        since: str | None = None,
    ) -> str:
        """Export to human-readable Markdown."""
        entries = self._query_entries(domain, entry_type, since)

        lines = [
            "# GreyMatter Knowledge Export",
            f"",
            f"Exported: {datetime.now().strftime('%Y-%m-%d %H:%M')}",
            f"Entries: {len(entries)}",
            "",
        ]

        if domain:
            lines.append(f"Domain filter: `{domain}`")
            lines.append("")

        # Group by domain
        by_domain: dict[str, list[dict]] = {}
        for e in entries:
            d = e.get("domain") or "general"
            by_domain.setdefault(d, []).append(e)

        for dom in sorted(by_domain):
            lines.append(f"## {dom}")
            lines.append("")
            for e in by_domain[dom]:
                lines.append(f"### {e['title']}")
                lines.append("")
                lines.append(f"- **Type**: {e.get('entry_type', 'unknown')}")
                lines.append(f"- **Scope**: {e.get('scope', 'cross-cutting')}")
                if e.get("tags"):
                    lines.append(f"- **Tags**: {e['tags']}")
                lines.append(f"- **Created**: {(e.get('created_at') or '')[:10]}")
                lines.append("")
                lines.append(e.get("content", ""))
                lines.append("")
                lines.append("---")
                lines.append("")

        return "\n".join(lines)

    def to_markdown_file(self, path: str, **kwargs) -> int:
        """Export to a Markdown file. Returns entry count."""
        md = self.to_markdown(**kwargs)
        with open(path, "w") as f:
            f.write(md)
        return md.count("### ")

    def _query_entries(
        self, domain: str | None, entry_type: str | None, since: str | None
    ) -> list[dict]:
        query = "SELECT * FROM knowledge_entries WHERE pruned_at IS NULL"
        params: list = []
        if domain:
            query += " AND domain = ?"
            params.append(domain)
        if entry_type:
            query += " AND entry_type = ?"
            params.append(entry_type)
        if since:
            query += " AND COALESCE(updated_at, created_at) >= ?"
            params.append(since)
        query += " ORDER BY domain, created_at"
        return self.db.execute(query, tuple(params))

    def _query_observations(self, since: str | None) -> list[dict]:
        query = "SELECT * FROM observations WHERE pruned = 0"
        params: list = []
        if since:
            query += " AND created_at >= ?"
            params.append(since)
        query += " ORDER BY created_at"
        return self.db.execute(query, tuple(params))


class KnowledgeImporter:
    """Import knowledge entries from JSON export."""

    def __init__(self, db: Database):
        self.db = db

    def from_json(self, data: dict[str, Any]) -> dict[str, Any]:
        """Import from a JSON dict (as produced by KnowledgeExporter.to_json).

        Returns summary with counts of imported, skipped (duplicates), errors.
        """
        if data.get("format") != "greymatter-export":
            return {"error": "Invalid format: expected greymatter-export"}

        entries = data.get("knowledge_entries", [])
        imported = 0
        skipped = 0
        errors = 0

        for entry in entries:
            try:
                # Check for duplicate by title + entry_type
                existing = self.db.execute_one(
                    "SELECT id FROM knowledge_entries WHERE title = ? AND entry_type = ? AND pruned_at IS NULL",
                    (entry.get("title", ""), entry.get("entry_type", "")),
                )
                if existing:
                    skipped += 1
                    continue

                new_id = generate_knowledge_id()
                try:
                    self.db.execute(
                        """INSERT INTO knowledge_entries
                           (id, entry_type, type, source, scope, domain, title, content,
                            valence, tags, created_at, updated_at)
                           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
                        (new_id, entry.get("entry_type", "reference"),
                         entry.get("entry_type", "reference"), "import",
                         entry.get("scope", "cross-cutting"),
                         entry.get("domain"),
                         entry.get("title", ""),
                         entry.get("content", ""),
                         entry.get("valence", "neutral"),
                         entry.get("tags"),
                         entry.get("created_at", datetime.now().isoformat()),
                         datetime.now().isoformat()),
                    )
                except Exception:
                    self.db.execute(
                        """INSERT INTO knowledge_entries
                           (id, entry_type, scope, domain, title, content,
                            valence, tags, created_at, updated_at)
                           VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
                        (new_id, entry.get("entry_type", "reference"),
                         entry.get("scope", "cross-cutting"),
                         entry.get("domain"),
                         entry.get("title", ""),
                         entry.get("content", ""),
                         entry.get("valence", "neutral"),
                         entry.get("tags"),
                         entry.get("created_at", datetime.now().isoformat()),
                         datetime.now().isoformat()),
                    )
                imported += 1
            except Exception as exc:
                errors += 1

        return {
            "imported": imported,
            "skipped": skipped,
            "errors": errors,
            "total": len(entries),
        }

    def from_json_file(self, path: str) -> dict[str, Any]:
        """Import from a JSON file."""
        with open(path) as f:
            data = json.load(f)
        return self.from_json(data)
