"""Tests for document management commands via Click test runner."""

import json

import pytest
from click.testing import CliRunner

from kb_search.cli import main
from kb_search.database import (
    SCHEMA_VERSION,
    get_connection,
    init_schema,
    insert_chunk,
    insert_document,
    insert_embedding,
    set_db_config,
    tag_document,
)


@pytest.fixture
def kb_env(tmp_path, monkeypatch):
    """Set up a test KB environment."""
    data_dir = tmp_path / ".kb"
    data_dir.mkdir()
    db_path = data_dir / "kb.db"

    conn = get_connection(db_path)
    init_schema(conn, 384)
    set_db_config(conn, "schema_version", str(SCHEMA_VERSION))
    set_db_config(conn, "model_name", "all-MiniLM-L6-v2")
    set_db_config(conn, "embedding_dim", "384")

    # Add a test document
    doc_id = insert_document(conn, "Test Doc", "/tmp/test.pdf", "abc123", "pdf")
    insert_chunk(conn, doc_id, 0, "This is chunk zero about Python")
    insert_chunk(conn, doc_id, 1, "This is chunk one about testing")
    tag_document(conn, doc_id, ["test", "pdf"])
    conn.commit()
    conn.close()

    monkeypatch.setenv("KB_DATA_DIR", str(data_dir))
    return data_dir


class TestList:
    def test_json_output(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["list", "--format", "json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert len(data) == 1
        assert data[0]["title"] == "Test Doc"
        assert data[0]["type"] == "pdf"

    def test_human_output(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["list", "--format", "human"])
        assert result.exit_code == 0
        assert "Test Doc" in result.output

    def test_filter_type(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["list", "--type", "markdown", "--format", "json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert len(data) == 0

    def test_filter_tags(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["list", "--tags", "test", "--format", "json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert len(data) == 1


class TestInfo:
    def test_json_output(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["info", "1", "--format", "json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert data["title"] == "Test Doc"
        assert data["chunk_count"] == 2
        assert "test" in data["tags"]

    def test_not_found(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["info", "999"])
        assert result.exit_code != 0
        assert "not found" in result.output.lower()


class TestRemove:
    def test_remove_with_yes(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["remove", "1", "--yes"])
        assert result.exit_code == 0
        assert "Removed" in result.output

        # Verify gone
        result = runner.invoke(main, ["list", "--format", "json"])
        data = json.loads(result.output)
        assert len(data) == 0

    def test_remove_not_found(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["remove", "999", "--yes"])
        assert result.exit_code != 0


class TestTags:
    def test_list_tags(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["tags", "--format", "json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        names = [t["name"] for t in data]
        assert "test" in names
        assert "pdf" in names

    def test_add_tag(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["tag", "1", "--add", "new"])
        assert result.exit_code == 0
        assert "Added" in result.output

    def test_remove_tag(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["tag", "1", "--remove", "test"])
        assert result.exit_code == 0
        assert "Removed" in result.output


class TestStatus:
    def test_json_output(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["status", "--format", "json"])
        assert result.exit_code == 0
        data = json.loads(result.output)
        assert data["model_name"] == "all-MiniLM-L6-v2"
        assert data["total_documents"] == 1
        assert data["total_chunks"] == 2

    def test_human_output(self, kb_env):
        runner = CliRunner()
        result = runner.invoke(main, ["status", "--format", "human"])
        assert result.exit_code == 0
        assert "all-MiniLM-L6-v2" in result.output

    def test_not_initialised(self, tmp_path, monkeypatch):
        monkeypatch.setenv("KB_DATA_DIR", str(tmp_path / "nonexistent"))
        runner = CliRunner()
        result = runner.invoke(main, ["status"])
        assert result.exit_code != 0
        assert "not initialised" in result.output.lower()
