"""Tests for the Giga dev bridge — handlers and GigaAdapter."""

from __future__ import annotations

import json
import pytest
from pathlib import Path

from vastian.bridges.giga_dev_bridge import handlers
from vastian.bridges.giga_dev_bridge.handlers import (
    _slugify,
    write_giga_plan,
    write_giga_neuron,
    GigaAdapter,
)


@pytest.fixture(autouse=True)
def _redirect_outbox(monkeypatch: pytest.MonkeyPatch, temp_dir: Path) -> None:
    """Point all outbox/inbox paths to temp dir."""
    monkeypatch.setattr(handlers, "OUTBOX_PLANS", temp_dir / "outbox" / "plans")
    monkeypatch.setattr(handlers, "OUTBOX_NEURONS", temp_dir / "outbox" / "neurons")
    monkeypatch.setattr(handlers, "INBOX_ROOT", temp_dir / "inbox")


class TestSlugify:
    def test_basic_slug(self) -> None:
        assert _slugify("Hello World") == "hello-world"

    def test_special_chars_removed(self) -> None:
        assert _slugify("My Plan!!! @#$") == "my-plan"

    def test_max_length_truncates(self) -> None:
        result = _slugify("a" * 100, max_len=10)
        assert len(result) == 10

    def test_empty_string(self) -> None:
        assert _slugify("") == ""


class TestWriteGigaPlan:
    def test_writes_json_to_outbox(self, temp_dir: Path) -> None:
        write_giga_plan("henry", "test-plan", "# My Plan\n- [ ] Task 1")
        plan_dir = temp_dir / "outbox" / "plans"
        files = list(plan_dir.glob("*.json"))
        assert len(files) == 1

    def test_plan_payload_fields(self, temp_dir: Path) -> None:
        write_giga_plan("henry", "cycle-review", "Review content", mind="work")
        plan_dir = temp_dir / "outbox" / "plans"
        f = list(plan_dir.glob("*.json"))[0]
        data = json.loads(f.read_text(encoding="utf-8"))
        assert data["key_name"] == "cycle-review"
        assert data["content"] == "Review content"
        assert data["mind"] == "work"
        assert data["created_by"] == "henry"
        assert "created_at" in data

    def test_returns_confirmation_message(self) -> None:
        result = write_giga_plan("henry", "my-plan", "content")
        assert "my-plan" in result
        assert "outbox" in result.lower()


class TestWriteGigaNeuron:
    def test_writes_json_to_outbox(self, temp_dir: Path) -> None:
        write_giga_neuron("orion", "Ops Status", "All loops healthy")
        neuron_dir = temp_dir / "outbox" / "neurons"
        files = list(neuron_dir.glob("*.json"))
        assert len(files) == 1

    def test_neuron_filename_contains_timestamp(self, temp_dir: Path) -> None:
        write_giga_neuron("orion", "Test Neuron", "Body text")
        neuron_dir = temp_dir / "outbox" / "neurons"
        f = list(neuron_dir.glob("*.json"))[0]
        # Filename should be like 20260206T123456_test-neuron.json
        assert "T" in f.stem  # timestamp separator

    def test_neuron_payload_fields(self, temp_dir: Path) -> None:
        write_giga_neuron(
            "orion", "Decision", "Use Protocol", selector_nl="architecture", mind="work"
        )
        neuron_dir = temp_dir / "outbox" / "neurons"
        f = list(neuron_dir.glob("*.json"))[0]
        data = json.loads(f.read_text(encoding="utf-8"))
        assert data["title"] == "Decision"
        assert data["body"] == "Use Protocol"
        assert data["selector_nl"] == "architecture"
        assert data["mind"] == "work"

    def test_returns_confirmation_message(self) -> None:
        result = write_giga_neuron("orion", "Test", "Body")
        assert "Test" in result
        assert "outbox" in result.lower()


class TestGigaAdapter:
    def test_write_plan_delegates_to_handler(self, temp_dir: Path) -> None:
        adapter = GigaAdapter()
        result = adapter.write_plan("henry", "test-key", "content")
        assert "test-key" in result
        assert len(list((temp_dir / "outbox" / "plans").glob("*.json"))) == 1

    def test_write_neuron_delegates_to_handler(self, temp_dir: Path) -> None:
        adapter = GigaAdapter()
        result = adapter.write_neuron("henry", "Title", "Body")
        assert "Title" in result
        assert len(list((temp_dir / "outbox" / "neurons").glob("*.json"))) == 1

    def test_pull_plans_reads_json_files(self, temp_dir: Path) -> None:
        adapter = GigaAdapter()
        plans_dir = temp_dir / "inbox" / "test-mind" / "plans"
        plans_dir.mkdir(parents=True)
        (plans_dir / "plan1.json").write_text(
            json.dumps({"key_name": "plan-alpha", "content": "Plan A"}),
            encoding="utf-8",
        )
        result = adapter.pull_plans("test-mind")
        assert len(result) == 1
        assert result[0]["key_name"] == "plan-alpha"
        assert result[0]["source"] == "giga"

    def test_pull_plans_skips_malformed_json(self, temp_dir: Path) -> None:
        adapter = GigaAdapter()
        plans_dir = temp_dir / "inbox" / "test-mind" / "plans"
        plans_dir.mkdir(parents=True)
        (plans_dir / "bad.json").write_text("NOT JSON", encoding="utf-8")
        (plans_dir / "good.json").write_text(json.dumps({"key_name": "ok"}), encoding="utf-8")
        result = adapter.pull_plans("test-mind")
        assert len(result) == 1

    def test_pull_plans_empty_dir(self, temp_dir: Path) -> None:
        adapter = GigaAdapter()
        result = adapter.pull_plans("nonexistent-mind")
        assert result == []

    def test_pull_neurons_reads_json_files(self, temp_dir: Path) -> None:
        adapter = GigaAdapter()
        neurons_dir = temp_dir / "inbox" / "test-mind" / "neurons"
        neurons_dir.mkdir(parents=True)
        (neurons_dir / "neuron1.json").write_text(
            json.dumps({"title": "Arch Decision", "body": "Use Protocol"}),
            encoding="utf-8",
        )
        result = adapter.pull_neurons("test-mind")
        assert len(result) == 1
        assert result[0]["title"] == "Arch Decision"
        assert result[0]["source"] == "giga"

    def test_pull_neurons_adds_pulled_at(self, temp_dir: Path) -> None:
        adapter = GigaAdapter()
        neurons_dir = temp_dir / "inbox" / "test-mind" / "neurons"
        neurons_dir.mkdir(parents=True)
        (neurons_dir / "n.json").write_text(
            json.dumps({"title": "T", "body": "B"}), encoding="utf-8"
        )
        result = adapter.pull_neurons("test-mind")
        assert "pulled_at" in result[0]

    def test_sync_inbox_returns_total_count(self, temp_dir: Path) -> None:
        adapter = GigaAdapter()
        plans_dir = temp_dir / "inbox" / "mind1" / "plans"
        plans_dir.mkdir(parents=True)
        neurons_dir = temp_dir / "inbox" / "mind1" / "neurons"
        neurons_dir.mkdir(parents=True)

        (plans_dir / "p1.json").write_text(json.dumps({"key": "p1"}), encoding="utf-8")
        (plans_dir / "p2.json").write_text(json.dumps({"key": "p2"}), encoding="utf-8")
        (neurons_dir / "n1.json").write_text(json.dumps({"title": "n1"}), encoding="utf-8")

        total = adapter.sync_inbox("mind1")
        assert total == 3
