"""Tests for extended collectors: Copilot, Windsurf, Aider."""

import json
import sqlite3
import tempfile
from pathlib import Path

from memotrail.collectors.copilot import parse_session_file as parse_copilot
from memotrail.collectors.copilot import find_session_files as find_copilot
from memotrail.collectors.windsurf import parse_session_file as parse_windsurf
from memotrail.collectors.windsurf import find_session_files as find_windsurf
from memotrail.collectors.aider import parse_session_file as parse_aider
from memotrail.collectors.aider import find_session_files as find_aider


def _create_vscdb(tmp_path: Path, key: str, value: str) -> Path:
    """Create a mock state.vscdb file with given key/value."""
    workspace_dir = tmp_path / "workspace1"
    workspace_dir.mkdir(parents=True)
    db_path = workspace_dir / "state.vscdb"

    conn = sqlite3.connect(str(db_path))
    conn.execute("CREATE TABLE ItemTable ([key] TEXT PRIMARY KEY, value TEXT)")
    conn.execute("INSERT INTO ItemTable VALUES (?, ?)", (key, value))
    conn.commit()
    conn.close()
    return db_path


# ── Copilot Tests ──────────────────────────────────────────

class TestCopilotCollector:
    def test_parse_empty_db(self, tmp_path):
        db_path = _create_vscdb(tmp_path, "unrelated.key", "{}")
        sessions = parse_copilot(db_path)
        assert sessions == []

    def test_parse_interactive_sessions(self, tmp_path):
        data = [
            {
                "exchanges": [
                    {"prompt": "How do I sort a list?", "response": "Use sorted() or .sort()"},
                    {"prompt": "What about reverse?", "response": "Pass reverse=True"},
                ]
            }
        ]
        db_path = _create_vscdb(tmp_path, "interactive.sessions", json.dumps(data))
        sessions = parse_copilot(db_path)
        assert len(sessions) >= 1
        assert len(sessions[0]["messages"]) == 4  # 2 user + 2 assistant

    def test_parse_copilot_chat_key(self, tmp_path):
        data = {
            "sessions": [
                {
                    "exchanges": [
                        {"prompt": "Explain decorators", "response": "Decorators are..."}
                    ]
                }
            ]
        }
        db_path = _create_vscdb(tmp_path, "github.copilot.chat", json.dumps(data))
        sessions = parse_copilot(db_path)
        assert len(sessions) >= 1

    def test_parse_response_blocks(self, tmp_path):
        data = [
            {
                "exchanges": [
                    {
                        "prompt": "Help",
                        "response": [
                            {"type": "markdown", "value": "Here's the answer"},
                            {"type": "markdown", "value": "More details"},
                        ],
                    }
                ]
            }
        ]
        db_path = _create_vscdb(tmp_path, "interactive.sessions", json.dumps(data))
        sessions = parse_copilot(db_path)
        assert len(sessions) >= 1
        assistant_msgs = [m for m in sessions[0]["messages"] if m["role"] == "assistant"]
        assert len(assistant_msgs) == 1
        assert "answer" in assistant_msgs[0]["content"]

    def test_find_session_files_empty(self, tmp_path):
        files = find_copilot(tmp_path)
        assert files == []

    def test_find_session_files(self, tmp_path):
        _create_vscdb(tmp_path, "test", "{}")
        files = find_copilot(tmp_path)
        assert len(files) == 1

    def test_infer_project_from_workspace_json(self, tmp_path):
        db_path = _create_vscdb(
            tmp_path, "interactive.sessions",
            json.dumps([{"exchanges": [{"prompt": "hi", "response": "hello"}]}]),
        )
        workspace_json = db_path.parent / "workspace.json"
        workspace_json.write_text(json.dumps({"folder": "file:///home/user/myproject"}))

        sessions = parse_copilot(db_path)
        assert len(sessions) >= 1
        assert sessions[0]["project"] == "myproject"


# ── Windsurf Tests ─────────────────────────────────────────

class TestWindsurfCollector:
    def test_parse_empty_db(self, tmp_path):
        db_path = _create_vscdb(tmp_path, "unrelated.key", "{}")
        sessions = parse_windsurf(db_path)
        assert sessions == []

    def test_parse_chatdata(self, tmp_path):
        data = [
            {
                "messages": [
                    {"role": "user", "content": "What is async?"},
                    {"role": "assistant", "content": "Async is..."},
                ]
            }
        ]
        db_path = _create_vscdb(
            tmp_path, "workbench.panel.aichat.view.aichat.chatdata", json.dumps(data)
        )
        sessions = parse_windsurf(db_path)
        assert len(sessions) >= 1
        assert len(sessions[0]["messages"]) == 2

    def test_parse_codeium_key(self, tmp_path):
        data = {
            "conversations": [
                {
                    "messages": [
                        {"role": "user", "content": "Help me"},
                        {"role": "assistant", "content": "Sure"},
                    ]
                }
            ]
        }
        db_path = _create_vscdb(tmp_path, "codeium.chatHistory", json.dumps(data))
        sessions = parse_windsurf(db_path)
        assert len(sessions) >= 1

    def test_parse_bubbles_format(self, tmp_path):
        data = [
            {
                "bubbles": [
                    {"type": "user", "text": "How do I..."},
                    {"type": "assistant", "text": "You can..."},
                ]
            }
        ]
        db_path = _create_vscdb(
            tmp_path, "workbench.panel.aichat.view.aichat.chatdata", json.dumps(data)
        )
        sessions = parse_windsurf(db_path)
        assert len(sessions) >= 1

    def test_find_session_files_empty(self, tmp_path):
        files = find_windsurf(tmp_path)
        assert files == []

    def test_parse_content_blocks(self, tmp_path):
        data = [
            {
                "messages": [
                    {
                        "role": "user",
                        "content": [
                            {"type": "text", "text": "Help me with Python"},
                        ],
                    },
                    {
                        "role": "assistant",
                        "content": "Python is great",
                    },
                ]
            }
        ]
        db_path = _create_vscdb(
            tmp_path, "workbench.panel.aichat.view.aichat.chatdata", json.dumps(data)
        )
        sessions = parse_windsurf(db_path)
        assert len(sessions) >= 1
        assert "Python" in sessions[0]["messages"][0]["content"]


# ── Aider Tests ────────────────────────────────────────────

class TestAiderCollector:
    def test_parse_empty_file(self, tmp_path):
        f = tmp_path / ".aider.chat.history.md"
        f.write_text("")
        sessions = parse_aider(f)
        assert sessions == []

    def test_parse_basic_session(self, tmp_path):
        content = """#### USER
How do I create a function?

#### ASSISTANT
Use the `def` keyword:

```python
def my_function():
    pass
```
"""
        f = tmp_path / "project" / ".aider.chat.history.md"
        f.parent.mkdir(parents=True)
        f.write_text(content)

        sessions = parse_aider(f)
        assert len(sessions) >= 1
        assert len(sessions[0]["messages"]) == 2
        assert sessions[0]["messages"][0]["role"] == "user"
        assert sessions[0]["messages"][1]["role"] == "assistant"

    def test_parse_multiple_sessions(self, tmp_path):
        content = """#### USER
First question

#### ASSISTANT
First answer

---

#### USER
Second question

#### ASSISTANT
Second answer
"""
        f = tmp_path / "project" / ".aider.chat.history.md"
        f.parent.mkdir(parents=True)
        f.write_text(content)

        sessions = parse_aider(f)
        assert len(sessions) == 2

    def test_infer_project_from_parent_dir(self, tmp_path):
        f = tmp_path / "my-awesome-project" / ".aider.chat.history.md"
        f.parent.mkdir(parents=True)
        f.write_text("#### USER\nhi\n\n#### ASSISTANT\nhello\n")

        sessions = parse_aider(f)
        assert len(sessions) >= 1
        assert sessions[0]["project"] == "my-awesome-project"

    def test_find_session_files_empty(self, tmp_path):
        files = find_aider(tmp_path)
        assert files == []

    def test_find_session_files(self, tmp_path):
        f = tmp_path / ".aider.chat.history.md"
        f.write_text("#### USER\ntest\n\n#### ASSISTANT\nok\n")
        files = find_aider(tmp_path)
        assert len(files) == 1

    def test_parse_multiline_messages(self, tmp_path):
        content = """#### USER
I need help with:
- item 1
- item 2
- item 3

#### ASSISTANT
Here's the solution:

1. First do this
2. Then do that
3. Finally, check results
"""
        f = tmp_path / "proj" / ".aider.chat.history.md"
        f.parent.mkdir(parents=True)
        f.write_text(content)

        sessions = parse_aider(f)
        assert len(sessions) >= 1
        user_msg = sessions[0]["messages"][0]
        assert "item 1" in user_msg["content"]
        assert "item 3" in user_msg["content"]

    def test_parse_nonexistent_file(self, tmp_path):
        f = tmp_path / "nonexistent.md"
        sessions = parse_aider(f)
        assert sessions == []


# ── Registry Tests ─────────────────────────────────────────

class TestCollectorRegistry:
    def test_registry_has_all_collectors(self):
        from memotrail.collectors import COLLECTORS
        assert "claude_code" in COLLECTORS
        assert "cursor" in COLLECTORS
        assert "copilot" in COLLECTORS
        assert "windsurf" in COLLECTORS
        assert "aider" in COLLECTORS

    def test_all_collectors_have_required_functions(self):
        from memotrail.collectors import COLLECTORS
        for name, collector in COLLECTORS.items():
            assert hasattr(collector, "find_session_files"), f"{name} missing find_session_files"
            assert hasattr(collector, "parse_session_file"), f"{name} missing parse_session_file"
