"""Shared fixtures for E2E test scenarios."""
from __future__ import annotations

from pathlib import Path
from unittest.mock import AsyncMock, patch

import pytest
from click.testing import CliRunner
from fastapi.testclient import TestClient


# ── Auth client fixture ──────────────────────────────────────

@pytest.fixture
def authed_client():
    """TestClient z auth headerem — potrzebny dla /observability/*."""
    from proxym.main import app
    with TestClient(app) as c:
        c.headers["Authorization"] = "Bearer sk-proxy-local-dev"
        yield c


# ── Project fixtures ─────────────────────────────────────────

@pytest.fixture
def tmp_projects(tmp_path):
    """3 testowe projekty + 1 hidden."""
    (tmp_path / "python-app" / ".git").mkdir(parents=True)
    (tmp_path / "python-app" / "pyproject.toml").write_text("[project]\nname='app'")
    (tmp_path / "js-app").mkdir()
    (tmp_path / "js-app" / "package.json").write_text(
        '{"name":"js-app","dependencies":{"react":"18"}}'
    )
    (tmp_path / "rust-app").mkdir()
    (tmp_path / "rust-app" / "Cargo.toml").write_text('[package]\nname = "rust-app"')
    (tmp_path / ".hidden").mkdir()
    return tmp_path


@pytest.fixture
def project_id(client, tmp_path):
    """Zarejestrowany projekt — rejestracja przez Python API
    (bypass HTTP POST /projects, który ma bug z @log_call + Pydantic body).
    """
    src = tmp_path / "test-proj"
    src.mkdir(exist_ok=True)
    (src / "pyproject.toml").write_text("[project]\nname='test-proj'")
    (src / ".git").mkdir()

    from proxym.dashboard._projects_api import _get_registry
    from proxym.projects import Project, SourceType
    project = Project(
        name="test-proj",
        source_type=SourceType.local,
        source_path=str(src),
        local_path=str(src),
    )
    created = _get_registry().add(project)
    return created.id


# ── Ticket fixtures ──────────────────────────────────────────

@pytest.fixture
def ticket_id(client, project_id):
    """Ticket powiązany z projektem."""
    r = client.post("/dashboard/tickets", json={
        "task": "napraw test fixture bug",
        "project_id": project_id,
    })
    assert r.status_code == 200, f"Failed to create ticket: {r.text}"
    return r.json()["id"]


@pytest.fixture
def failed_ticket_id(client, project_id):
    """Ticket ze statusem cancelled (brak 'failed' w TicketStatus enum)."""
    r = client.post("/dashboard/tickets", json={
        "task": "ticket that will fail",
        "project_id": project_id,
    })
    assert r.status_code == 200, f"Failed to create ticket: {r.text}"
    tid = r.json()["id"]
    client.put(f"/dashboard/tickets/{tid}", json={"status": "cancelled"})
    client.post(f"/dashboard/tickets/{tid}/comment", json={
        "author": "aider",
        "content": "aider ❌ failed — SyntaxError: unexpected indent line 42",
    })
    return tid


@pytest.fixture
def repaired_ticket_id(client, project_id):
    """Ticket naprawiony przez repair-agent."""
    r = client.post("/dashboard/tickets", json={
        "task": "ticket repaired by agent",
        "project_id": project_id,
    })
    assert r.status_code == 200, f"Failed to create ticket: {r.text}"
    tid = r.json()["id"]
    client.put(f"/dashboard/tickets/{tid}", json={"status": "done"})
    client.post(f"/dashboard/tickets/{tid}/comment", json={
        "author": "repair-agent",
        "content": "Diagnosed: NoneType access. Applied null-check fix. Tests pass.",
    })
    return tid


# ── Sprint fixtures ──────────────────────────────────────────

@pytest.fixture
def sprint_id(client):
    """Sprint testowy."""
    r = client.post("/dashboard/sprints", json={"name": "Test Sprint"})
    assert r.status_code == 200
    return r.json()["id"]


@pytest.fixture
def sprint_ticket_ids(client, project_id, sprint_id):
    """5 ticketów w sprincie z różnymi narzędziami."""
    ids = []
    tools = ["aider", "aider", "claude-code", "aider", "claude-code"]
    for i, tool in enumerate(tools):
        r = client.post("/dashboard/tickets", json={
            "task": f"Sprint task {i+1}",
            "project_id": project_id,
            "sprint_id": sprint_id,
            "tool": tool,
        })
        ids.append(r.json()["id"])
    return ids


# ── Mock adapter fixtures ────────────────────────────────────

@pytest.fixture
def mock_adapter_success():
    """Mock adapter zwracający sukces."""
    with patch("proxym.tools.adapters.get_adapter") as mock_get:
        result = type("Result", (), {
            "exit_code": 0,
            "stdout": "3 files changed",
            "stderr": "",
            "duration_seconds": 12.5,
            "files_changed": ["src/a.py", "src/b.py"],
            "summary": lambda self: {
                "exit_code": 0, "stdout": "3 files changed",
                "files_changed": ["src/a.py", "src/b.py"],
                "duration_seconds": 12.5,
            },
        })()
        adapter = AsyncMock()
        adapter.run.return_value = result
        mock_get.return_value = adapter
        yield mock_get


@pytest.fixture
def mock_adapter_failure():
    """Mock adapter zwracający błąd."""
    with patch("proxym.tools.adapters.get_adapter") as mock_get:
        result = type("Result", (), {
            "exit_code": 1,
            "stdout": "",
            "stderr": "SyntaxError: unexpected indent line 42",
            "duration_seconds": 3.0,
            "files_changed": [],
            "summary": lambda self: {
                "exit_code": 1, "stderr": "SyntaxError: unexpected indent line 42",
                "files_changed": [], "duration_seconds": 3.0,
            },
        })()
        adapter = AsyncMock()
        adapter.run.return_value = result
        mock_get.return_value = adapter
        yield mock_get


@pytest.fixture
def mock_adapter_timeout():
    """Mock adapter z timeoutem."""
    with patch("proxym.tools.adapters.get_adapter") as mock_get:
        adapter = AsyncMock()
        adapter.run.side_effect = TimeoutError("Tool execution timed out after 300s")
        mock_get.return_value = adapter
        yield mock_get


# ── CLI fixtures ─────────────────────────────────────────────

@pytest.fixture
def runner():
    """Click CliRunner (izolowany od systemu)."""
    return CliRunner()


@pytest.fixture
def cli():
    """Proxym CLI entry point."""
    from proxym.ctl import cli as proxym_cli
    return proxym_cli
