from pathlib import Path
import sys
from unittest.mock import patch

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from backend.auth import create_token
from backend.db import DB_FILE, init_db
from backend.main import app
from fastapi.testclient import TestClient


@pytest.fixture(autouse=True)
def reset_db():
    if DB_FILE.exists():
        DB_FILE.unlink()
    init_db()
    yield


@pytest.fixture
def client():
    return TestClient(app)


@pytest.fixture
def auth_headers(client):
    response = client.post("/api/auth/login", json={"username": "user", "password": "password"})
    assert response.status_code == 200
    token = response.json()["token"]
    return {"Authorization": f"Bearer {token}"}


def test_login_success(client):
    response = client.post("/api/auth/login", json={"username": "user", "password": "password"})
    assert response.status_code == 200
    body = response.json()
    assert "token" in body
    assert isinstance(body["token"], str)
    assert len(body["token"]) > 0


def test_login_failure(client):
    response = client.post("/api/auth/login", json={"username": "user", "password": "wrong"})
    assert response.status_code == 401


def test_list_boards_requires_auth(client):
    response = client.get("/api/boards")
    assert response.status_code == 401


def test_update_board_requires_auth(client):
    response = client.put("/api/boards/1", json={"board": {"columns": [], "cards": {}}})
    assert response.status_code == 401


def test_list_boards_default_user(client, auth_headers):
    response = client.get("/api/boards", headers=auth_headers)
    assert response.status_code == 200
    body = response.json()
    assert "boards" in body
    assert len(body["boards"]) == 1
    assert body["boards"][0]["name"] == "My Board"


def test_get_board_default_user(client, auth_headers):
    boards = client.get("/api/boards", headers=auth_headers).json()["boards"]
    board_id = boards[0]["id"]
    response = client.get(f"/api/boards/{board_id}", headers=auth_headers)
    assert response.status_code == 200
    body = response.json()
    assert "board" in body
    assert len(body["board"].get("columns", [])) == 5


def test_update_board_persists(client, auth_headers):
    boards = client.get("/api/boards", headers=auth_headers).json()["boards"]
    board_id = boards[0]["id"]

    board = client.get(f"/api/boards/{board_id}", headers=auth_headers).json()["board"]
    board["columns"][0]["title"] = "Updated Backlog"

    update_response = client.put(
        f"/api/boards/{board_id}", json={"board": board}, headers=auth_headers
    )
    assert update_response.status_code == 200
    assert update_response.json()["board"]["columns"][0]["title"] == "Updated Backlog"

    second_response = client.get(f"/api/boards/{board_id}", headers=auth_headers)
    assert second_response.status_code == 200
    assert second_response.json()["board"]["columns"][0]["title"] == "Updated Backlog"


def test_create_board(client, auth_headers):
    response = client.post("/api/boards", json={"name": "Sprint 2"}, headers=auth_headers)
    assert response.status_code == 200
    body = response.json()
    assert body["name"] == "Sprint 2"
    assert "id" in body

    boards = client.get("/api/boards", headers=auth_headers).json()["boards"]
    assert len(boards) == 2


def test_get_board_invalid_token(client):
    response = client.get("/api/boards", headers={"Authorization": "Bearer invalidtoken"})
    assert response.status_code == 401


def test_get_board_not_found(client, auth_headers):
    response = client.get("/api/boards/99999", headers=auth_headers)
    assert response.status_code == 404


def test_ai_route_returns_answer(client):
    with patch("backend.openrouter.call_openrouter_json", return_value={
        "choices": [{"message": {"content": "4"}}]
    }):
        response = client.post("/api/ai/test", json={"prompt": "2+2"})

    assert response.status_code == 200
    body = response.json()
    assert body["success"] is True
    assert body["answer"] == "4"
    assert body["prompt"] == "2+2"
    assert body["model"] == "openai/gpt-oss-120b"


def test_ai_route_handles_error_gracefully(client):
    with patch("backend.openrouter.call_openrouter_json", side_effect=RuntimeError("mock failure")):
        response = client.post("/api/ai/test", json={"prompt": "2+2"})

    assert response.status_code == 200
    body = response.json()
    assert body["success"] is False
    assert body["answer"] == ""
    assert body["error"] is not None


def test_ai_kanban_route_updates_board(client, auth_headers):
    boards = client.get("/api/boards", headers=auth_headers).json()["boards"]
    board_id = boards[0]["id"]
    board = client.get(f"/api/boards/{board_id}", headers=auth_headers).json()["board"]

    response_payload = {
        "choices": [
            {
                "message": {
                    "content": {
                        "answer": "Added a new card.",
                        "board": {
                            "columns": board["columns"],
                            "cards": board["cards"],
                        },
                    }
                }
            }
        ]
    }

    with patch("backend.openrouter.call_openrouter_json", return_value=response_payload):
        response = client.post(
            "/api/ai/kanban",
            json={"board": board, "prompt": "Please update the board."},
            headers=auth_headers,
        )

    assert response.status_code == 200
    body = response.json()
    assert body["success"] is True
    assert body["updated"] is True
    assert "board" in body
    assert body["answer"] == "Added a new card."


def test_ai_kanban_route_handles_invalid_structured_response(client, auth_headers):
    boards = client.get("/api/boards", headers=auth_headers).json()["boards"]
    board_id = boards[0]["id"]
    board = client.get(f"/api/boards/{board_id}", headers=auth_headers).json()["board"]

    response_payload = {
        "choices": [{"message": {"content": "This is not valid JSON"}}]
    }

    with patch("backend.openrouter.call_openrouter_json", return_value=response_payload):
        response = client.post(
            "/api/ai/kanban",
            json={"board": board, "prompt": "Please update the board."},
            headers=auth_headers,
        )

    assert response.status_code == 200
    body = response.json()
    assert body["success"] is False
    assert body["updated"] is False
    assert body["error"] is not None


def test_ai_kanban_requires_auth(client):
    response = client.post(
        "/api/ai/kanban",
        json={"board": {"columns": [], "cards": {}}, "prompt": "test"},
    )
    assert response.status_code == 401
