# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# Licensed under the MIT License

"""Tests for memory import into the MemoryTree."""

from dataclasses import dataclass, field
from pathlib import Path
from unittest.mock import MagicMock

import pytest

from familiar.core.memory_import import (
    import_brain_memories,
    import_file_metadata,
    import_markdown_memories,
)
from familiar.core.memory_tree import MemoryTree


@pytest.fixture
def tree(tmp_path):
    return MemoryTree(db_path=tmp_path / "import_test.db")


# ── Markdown Import ──


@pytest.fixture
def markdown_dir(tmp_path):
    """Create a fake markdown memories directory."""
    user_dir = tmp_path / "memories" / "default"
    user_dir.mkdir(parents=True)

    # File with frontmatter
    (user_dir / "sourdough-recipe.md").write_text(
        "---\n"
        "topic: sourdough-recipe\n"
        "created: '2026-03-10T12:00:00'\n"
        "updated: '2026-03-10T12:00:00'\n"
        "tags:\n- recipe\n- baking\n"
        "aliases: []\n"
        "source_memories:\n- conversation:abc\n"
        "provenance:\n  author: {name: '', orcid: ''}\n"
        "  license: proprietary\n  consent: owner\n"
        "revision: 1\n"
        "---\n"
        "## Sourdough Recipe\n\n"
        "Mix flour and water. Feed daily.\n",
        encoding="utf-8",
    )

    # File without frontmatter
    (user_dir / "quick-note.md").write_text(
        "Just a quick note about something.\n",
        encoding="utf-8",
    )

    # Empty file
    (user_dir / "empty.md").write_text("", encoding="utf-8")

    return tmp_path / "memories"


class TestMarkdownImport:
    def test_import_with_frontmatter(self, tree, markdown_dir):
        stats = import_markdown_memories(tree, markdown_dir, user_id="default")
        assert stats["imported"] >= 1
        results = tree.search("sourdough")
        assert len(results) >= 1
        entry = results[0]
        assert "recipe" in entry.tags or "baking" in entry.tags
        assert entry.tier == "archival"

    def test_import_without_frontmatter(self, tree, markdown_dir):
        stats = import_markdown_memories(tree, markdown_dir, user_id="default")
        assert stats["imported"] >= 2
        results = tree.search("quick note")
        assert len(results) >= 1

    def test_import_idempotent(self, tree, markdown_dir):
        stats1 = import_markdown_memories(tree, markdown_dir, user_id="default")
        imported_first = stats1["imported"]
        assert imported_first >= 2  # At least the two non-empty files
        stats2 = import_markdown_memories(tree, markdown_dir, user_id="default")
        assert stats2["imported"] == 0  # Nothing new on second run
        assert stats2["skipped"] >= imported_first

    def test_import_empty_dir(self, tree, tmp_path):
        empty = tmp_path / "empty_memories"
        stats = import_markdown_memories(tree, empty, user_id="default")
        assert stats["imported"] == 0

    def test_import_nonexistent_dir(self, tree, tmp_path):
        stats = import_markdown_memories(tree, tmp_path / "nonexistent", user_id="default")
        assert stats["imported"] == 0

    def test_import_preserves_file_path(self, tree, markdown_dir):
        import_markdown_memories(tree, markdown_dir, user_id="default")
        results = tree.search("sourdough")
        assert results[0].file_path is not None
        assert "sourdough" in results[0].file_path

    def test_import_adds_provenance_tags(self, tree, markdown_dir):
        import_markdown_memories(tree, markdown_dir, user_id="default")
        results = tree.search("sourdough")
        assert "imported" in results[0].tags
        assert "markdown" in results[0].tags

    def test_import_source_from_frontmatter(self, tree, markdown_dir):
        import_markdown_memories(tree, markdown_dir, user_id="default")
        results = tree.search("sourdough")
        assert results[0].source == "conversation:abc"


# ── Brain Import ──


@dataclass
class _FakeMemoryEntry:
    key: str
    value: str
    category: str = "fact"
    created_at: str = "2026-03-10"
    updated_at: str = "2026-03-10"
    source: str = ""
    importance: int = 5


class _FakeMemory:
    def __init__(self, entries: dict):
        self.memories = entries

    def recall_all(self):
        return self.memories


class TestBrainImport:
    def test_import_basic(self, tree):
        mem = _FakeMemory(
            {
                "user_name": _FakeMemoryEntry(
                    key="user_name",
                    value="George",
                    category="user_info",
                    importance=9,
                    source="extracted/web",
                ),
                "preference": _FakeMemoryEntry(
                    key="preference",
                    value="dark roast coffee",
                    category="preference",
                    importance=5,
                ),
            }
        )
        stats = import_brain_memories(tree, mem)
        assert stats["imported"] == 2
        results = tree.search("George")
        assert len(results) >= 1
        assert results[0].tier == "working"

    def test_import_importance_scaled(self, tree):
        mem = _FakeMemory(
            {
                "high": _FakeMemoryEntry(key="high", value="v", importance=10),
            }
        )
        import_brain_memories(tree, mem)
        results = tree.list_by_tier("working")
        assert results[0].importance == 1.0

    def test_import_preserves_category_tag(self, tree):
        mem = _FakeMemory(
            {
                "test": _FakeMemoryEntry(key="test", value="val", category="user_info"),
            }
        )
        import_brain_memories(tree, mem)
        results = tree.list_by_tier("working")
        assert "user_info" in results[0].tags

    def test_import_idempotent(self, tree):
        mem = _FakeMemory(
            {
                "x": _FakeMemoryEntry(key="x", value="y"),
            }
        )
        stats1 = import_brain_memories(tree, mem)
        stats2 = import_brain_memories(tree, mem)
        assert stats1["imported"] == 1
        assert stats2["skipped"] == 1
        assert stats2["imported"] == 0

    def test_import_empty(self, tree):
        mem = _FakeMemory({})
        stats = import_brain_memories(tree, mem)
        assert stats["imported"] == 0


# ── FileStore Import ──


@dataclass
class _FakeFileRecord:
    file_id: str = "file-001"
    job_class: str = "nonprofit"
    record_type: str = "grants"
    record_id: str = "grant-1"
    filename: str = "application.pdf"
    mime_type: str = "application/pdf"
    size_bytes: int = 12345
    sha256: str = "abc123"
    stored_at: str = "2026-03-10"
    description: str = "Grant application document"


class _FakeFileStore:
    def __init__(self, files: list):
        self._files = files

    def search(self, query="", limit=10000):
        return self._files


class TestFileImport:
    def test_import_basic(self, tree):
        fs = _FakeFileStore([_FakeFileRecord()])
        stats = import_file_metadata(tree, fs)
        assert stats["imported"] == 1
        results = tree.search("application.pdf")
        assert len(results) >= 1
        entry = results[0]
        assert entry.tier == "long"
        assert entry.meta["file_id"] == "file-001"
        assert "file" in entry.tags

    def test_import_mime_tag(self, tree):
        fs = _FakeFileStore(
            [
                _FakeFileRecord(mime_type="image/png", filename="photo.png"),
            ]
        )
        import_file_metadata(tree, fs)
        results = tree.search("photo.png")
        assert "image" in results[0].tags

    def test_import_idempotent(self, tree):
        fs = _FakeFileStore([_FakeFileRecord()])
        stats1 = import_file_metadata(tree, fs)
        stats2 = import_file_metadata(tree, fs)
        assert stats1["imported"] == 1
        assert stats2["skipped"] == 1

    def test_import_empty(self, tree):
        fs = _FakeFileStore([])
        stats = import_file_metadata(tree, fs)
        assert stats["imported"] == 0

    def test_import_multiple_files(self, tree):
        fs = _FakeFileStore(
            [
                _FakeFileRecord(file_id="f1", filename="doc1.pdf"),
                _FakeFileRecord(file_id="f2", filename="doc2.pdf"),
                _FakeFileRecord(file_id="f3", filename="photo.jpg", mime_type="image/jpeg"),
            ]
        )
        stats = import_file_metadata(tree, fs)
        assert stats["imported"] == 3
