import os
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Dict

import pytest
from fastapi.testclient import TestClient

PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

os.environ.setdefault("APPWRITE_ENDPOINT", "http://localhost/v1")
os.environ.setdefault("APPWRITE_PROJECT_ID", "test-project")
os.environ.setdefault("APPWRITE_API_KEY", "test-key")
os.environ.setdefault("APPWRITE_DATABASE_ID", "test-db")
os.environ.setdefault("APPWRITE_COLLECTION_CARRINHOS_ID", "test-carts")
os.environ.setdefault("APPWRITE_COLLECTION_PEDIDOS_ID", "test-orders")
os.environ.setdefault("APPWRITE_COLLECTION_PRODUTOS_CATALOGO_ID", "test-produtos")
os.environ.setdefault("APPWRITE_COLLECTION_LABORATORIOS_ID", "test-labs")
os.environ.setdefault("APPWRITE_COLLECTION_CATEGORIAS_ID", "test-categorias")
os.environ.setdefault("APPWRITE_COLLECTION_SUBCATEGORIAS_ID", "test-subcat")
os.environ.setdefault("APPWRITE_COLLECTION_PAGAMENTOS_ID", "test-payments")
os.environ.setdefault("APPWRITE_COLLECTION_PRODUTOS_ESTOQUE_ID", "test-produtos-estoque")
os.environ.setdefault("APPWRITE_COLLECTION_PRODUTOS_VENDA_ID", "test-produtos-venda")
os.environ.setdefault("APPWRITE_COLLECTION_USUARIOS_DATA_ID", "test-usuarios-data")
os.environ.setdefault("APPWRITE_COLLECTION_USUARIOS_PERFIL_ID", "test-usuarios-perfil")
os.environ.setdefault("APPWRITE_COLLECTION_USUARIO_EMPRESA_PERFIS_ID", "test-usuario-empresa-perfis")
os.environ.setdefault("APPWRITE_COLLECTION_FATURAS_ID", "test-faturas")
os.environ.setdefault("APPWRITE_COLLECTION_USUARIOS_ID", "test-users")
os.environ.setdefault("APPWRITE_COLLECTION_EMPRESAS_ID", "test-companies")
os.environ.setdefault("APPWRITE_COLLECTION_EMPRESAS_DADOS_ID", "test-companies-data")
os.environ.setdefault("APPWRITE_COLLECTION_EMPRESAS_SOCIOS_ID", "test-empresas-socios")
os.environ.setdefault("APPWRITE_COLLECTION_ENDERECOS_ID", "test-addresses")
os.environ.setdefault("APPWRITE_COLLECTION_ENTREGAS_ID", "test-entregas")
os.environ.setdefault("JWT_SECRET", "test-secret")
os.environ.setdefault("JWT_ALGORITHM", "HS256")
os.environ.setdefault("SECURITY_API_KEY", "")

from src.app.main import app
from src.core.deps import get_categorias_service, require_api_key, require_user
from src.modules.categorias.schemas import CategoriaCreate, CategoriaOut, CategoriaUpdate
from src.modules.categorias.service import _slugify


class InMemoryCategoriasService:
    def __init__(self) -> None:
        self._items: Dict[str, Dict[str, object]] = {}
        self._counter = 0

    async def list(
        self,
        page: int,
        limit: int | None,
        q: str | None,
        sort: str | None,
        order: str | None,
    ) -> Dict[str, object]:
        items = list(self._items.values())
        total = len(items)
        return {
            "items": [CategoriaOut(**item).model_dump() for item in items],
            "total": total,
        }

    async def get(self, categoria_id: str) -> CategoriaOut:
        if categoria_id not in self._items:
            raise AssertionError("Categoria não encontrada nos testes")
        return CategoriaOut(**self._items[categoria_id])

    async def create(self, payload: CategoriaCreate) -> CategoriaOut:
        data = payload.model_dump(exclude_unset=True)
        nome = data.get("nome")
        slug = data.get("slug") or (_slugify(nome) if nome else None)
        if not slug:
            raise AssertionError("Falha ao gerar slug")
        for item in self._items.values():
            if item["slug"] == slug:
                from fastapi import HTTPException, status

                raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Categoria já existe")
        self._counter += 1
        identifier = f"cat_{self._counter}"
        timestamp = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
        record = {
            "id": identifier,
            "nome": nome,
            "slug": slug,
            "subcategorias": None,
            "produtos_catalogo": None,
            "createdAt": timestamp,
            "updatedAt": timestamp,
        }
        self._items[identifier] = record
        return CategoriaOut(**record)

    async def update(self, categoria_id: str, payload: CategoriaUpdate) -> CategoriaOut:
        if categoria_id not in self._items:
            raise AssertionError("Categoria não encontrada nos testes")
        stored = self._items[categoria_id].copy()
        data = payload.model_dump(exclude_unset=True)
        if "nome" in data and data["nome"] is not None:
            stored["nome"] = data["nome"]
        if "slug" in data and data["slug"] is not None:
            stored["slug"] = data["slug"]
        stored["updatedAt"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
        self._items[categoria_id] = stored
        return CategoriaOut(**stored)

    async def delete(self, categoria_id: str) -> None:
        self._items.pop(categoria_id, None)


@pytest.fixture()
def test_client() -> TestClient:
    service = InMemoryCategoriasService()

    def override_service() -> InMemoryCategoriasService:
        return service

    app.dependency_overrides[get_categorias_service] = override_service
    app.dependency_overrides[require_api_key] = lambda: None
    app.dependency_overrides[require_user] = lambda: {"id": "user_1"}

    client = TestClient(app)
    yield client

    app.dependency_overrides.clear()
    client.close()


def test_create_categoria_generates_slug_when_empty(test_client: TestClient) -> None:
    response = test_client.post("/api/v1/categorias", json={"nome": "Summer Wear", "slug": ""})
    assert response.status_code == 201
    body = response.json()
    assert body["slug"] == _slugify("Summer Wear")


def test_list_categorias_returns_created_items(test_client: TestClient) -> None:
    test_client.post("/api/v1/categorias", json={"nome": "Sapatos", "slug": "sapatos"})
    test_client.post("/api/v1/categorias", json={"nome": "Chapeus", "slug": "chapeus"})

    response = test_client.get("/api/v1/categorias")
    assert response.status_code == 200
    data = response.json()
    assert data["total"] == 2
    assert len(data["items"]) == 2


def test_get_categoria_returns_item(test_client: TestClient) -> None:
    creation = test_client.post("/api/v1/categorias", json={"nome": "Bolsas", "slug": "bolsas"})
    identifier = creation.json()["id"]

    response = test_client.get(f"/api/v1/categorias/{identifier}")
    assert response.status_code == 200
    assert response.json()["id"] == identifier


def test_delete_categoria_removes_item(test_client: TestClient) -> None:
    creation = test_client.post("/api/v1/categorias", json={"nome": "Cintos", "slug": "cintos"})
    identifier = creation.json()["id"]

    response = test_client.delete(f"/api/v1/categorias/{identifier}")
    assert response.status_code == 204

    list_response = test_client.get("/api/v1/categorias")
    assert list_response.json()["total"] == 0


def test_create_categoria_conflict(test_client: TestClient) -> None:
    payload = {"nome": "Cachecois", "slug": "cachecois"}
    first = test_client.post("/api/v1/categorias", json=payload)
    assert first.status_code == 201

    second = test_client.post("/api/v1/categorias", json=payload)
    assert second.status_code == 409
    assert second.json()["detail"] == "Categoria já existe"
