from __future__ import annotations

from typing import Any

from fastapi import APIRouter, Depends, Query, status

from src.core.deps import get_produtos_catalogo_service, require_api_key
from src.modules.produtos_catalogo.schemas import (
    ProdutoCatalogoAppwriteDocument,
    ProdutoCatalogoCreateRequest,
    ProdutoCatalogoDocumentOut,
    ProdutoCatalogoOut,
    ProdutoCatalogoPublicOut,
    ProdutoCatalogoUpdateRequest,
    ProdutosCatalogoDocumentsResponse,
)
from src.modules.produtos_catalogo.service import ProdutosCatalogoService

router = APIRouter(prefix="/api/v1/produtos-catalogo", tags=["Produtos Catálogo"])


@router.get(
    "",
    summary="Listar produtos de catálogo",
    description=(
        "Retorna uma lista paginada de produtos do catálogo com filtros por relações, "
        "faixas de preço e busca textual."
    ),
    response_model=ProdutosCatalogoDocumentsResponse,
    responses={
        status.HTTP_200_OK: {
            "description": "Resposta bem-sucedida",
            "content": {
                "application/json": {
                    "example": {
                        "total": 1,
                        "documents": [
                            {
                                "codigo_ean": "7891000000001",
                                "codigo_interno": "INT-001",
                                "nome": "Dipirona 500mg 20cs",
                                "descricao": "Analgésico e antitérmico",
                                "preco_base": 12.9,
                                "preco_fabrica": 8.5,
                                "pmc": 10.9,
                                "desconto_comercial": 5.0,
                                "valor_substituicao_tributaria": 0.0,
                                "preco_nf": 9.2,
                                "$id": "document_id",
                                "$sequence": 1,
                                "$databaseId": "database_id",
                                "$collectionId": "collection_id",
                                "$createdAt": "2024-01-01T00:00:00.000+00:00",
                                "$updatedAt": "2024-01-01T00:00:00.000+00:00",
                                "$permissions": [],
                                "laboratorio": "lab_123",
                                "categoria": "cat_10",
                                "lab_nome": "EMS",
                                "cat_nome": "Medicamento",
                                "subcategoria": "sub_55",
                            }
                        ],
                    }
                }
            },
        },
        status.HTTP_400_BAD_REQUEST: {
            "description": "Parâmetros de consulta inválidos",
            "content": {"application/json": {"example": {"detail": "Invalid sort field."}}},
        },
    },
)
async def list_produtos_catalogo(
    page: int = Query(1, ge=1),
    limit: int | None = Query(None, ge=1, le=100),
    q: str | None = Query(None, min_length=1),
    sort: str | None = Query(None),
    order: str | None = Query(None, pattern="^(?i)(asc|desc)$"),
    laboratorioId: str | None = Query(None),
    categoriaId: str | None = Query(None),
    subcategoriaId: str | None = Query(None),
    preco_min: float | None = Query(None, ge=0),
    preco_max: float | None = Query(None, ge=0),
    pmc_min: float | None = Query(None, ge=0),
    pmc_max: float | None = Query(None, ge=0),
    _: None = Depends(require_api_key),
    service: ProdutosCatalogoService = Depends(get_produtos_catalogo_service),
) -> ProdutosCatalogoDocumentsResponse:
    normalized_order = order.lower() if order else None
    result = await service.list(
        page=page,
        limit=limit,
        q=q,
        sort=sort,
        order=normalized_order,
        laboratorio_id=laboratorioId,
        categoria_id=categoriaId,
        subcategoria_id=subcategoriaId,
        preco_min=preco_min,
        preco_max=preco_max,
        pmc_min=pmc_min,
        pmc_max=pmc_max,
    )

    documents = [ProdutoCatalogoDocumentOut(**document) for document in result.get("documents", [])]

    return ProdutosCatalogoDocumentsResponse(
        total=result.get("total", len(documents)),
        documents=documents,
    )


@router.get(
    "/{produto_id}",
    summary="Detalhar produto de catálogo",
    description="Busca um produto de catálogo pelo identificador, retornando os dados comerciais padronizados.",
    response_model=ProdutoCatalogoPublicOut,
    responses={
        status.HTTP_200_OK: {
            "description": "Produto localizado",
            "content": {
                "application/json": {
                    "example": {
                        "codigo_ean": "7891000000001",
                        "codigo_interno": "INT-001",
                        "nome": "Dipirona 500mg 20cs",
                        "descricao": "Analgésico e antitérmico",
                        "preco_base": 12.9,
                        "preco_fabrica": 8.5,
                        "pmc": 10.9,
                        "desconto_comercial": 5.0,
                        "valor_substituicao_tributaria": 0.0,
                        "preco_nf": 9.2,
                        "laboratorio": "lab_123",
                        "categoria": "cat_10",
                        "lab_nome": "EMS",
                        "cat_nome": "Medicamento",
                        "subcategoria": "sub_55",
                    }
                }
            },
        },
        status.HTTP_404_NOT_FOUND: {
            "description": "Produto não encontrado",
            "content": {
                "application/json": {
                    "example": {"detail": "Produto catálogo não encontrado."}
                }
            },
        },
    },
)
async def get_produto_catalogo(
    produto_id: str,
    _: None = Depends(require_api_key),
    service: ProdutosCatalogoService = Depends(get_produtos_catalogo_service),
) -> ProdutoCatalogoPublicOut:
    produto = await service.get(produto_id)
    return _map_to_public_response(produto)


@router.get(
    "/codigo-ean/{codigo_ean}",
    summary="Detalhar produto de catálogo por código EAN",
    description="Busca um produto de catálogo utilizando o código de barras (EAN).",
    response_model=ProdutoCatalogoPublicOut,
    responses={
        status.HTTP_200_OK: {
            "description": "Produto localizado",
            "content": {
                "application/json": {
                    "example": {
                        "codigo_ean": "7898148305100",
                        "codigo_interno": "INT-010",
                        "nome": "Produto Catálogo",
                        "descricao": "Descrição do produto",
                        "preco_base": 15.5,
                        "preco_fabrica": 11.2,
                        "pmc": 16.9,
                        "desconto_comercial": 3.0,
                        "valor_substituicao_tributaria": 0.0,
                        "preco_nf": 12.3,
                        "laboratorio": "lab_321",
                        "categoria": "cat_22",
                        "lab_nome": "EMS",
                        "cat_nome": "Medicamento",
                        "subcategoria": "sub_90",
                    }
                }
            },
        },
        status.HTTP_404_NOT_FOUND: {
            "description": "Produto não encontrado",
            "content": {
                "application/json": {
                    "example": {"detail": "Produto catálogo não encontrado."}
                }
            },
        },
    },
)
async def get_produto_catalogo_por_codigo_ean(
    codigo_ean: str,
    _: None = Depends(require_api_key),
    service: ProdutosCatalogoService = Depends(get_produtos_catalogo_service),
) -> ProdutoCatalogoPublicOut:
    produto = await service.get_by_codigo_ean(codigo_ean)
    return _map_to_public_response(produto)


def _map_to_public_response(produto: ProdutoCatalogoOut | dict[str, Any]) -> ProdutoCatalogoPublicOut:
    if isinstance(produto, ProdutoCatalogoOut):
        document_id = produto.id
        codigo_barras = produto.codigo_barras
        codigo_interno = produto.codigo_interno
        nome = produto.nome
        descricao = produto.descricao
        preco_consumidor = produto.preco_consumidor
        preco_fabrica = produto.preco_fabrica
        pmc = produto.pmc
        desconto_comercial = produto.desconto_comercial
        valor_substituicao_tributaria = produto.valor_substituicao_tributaria
        preco_nf = produto.preco_nf
        collection_id = produto.collectionId
        laboratorio = produto.laboratorioId
        categoria = produto.categoriaId
        lab_nome = produto.lab_nome
        cat_nome = produto.cat_nome
        subcategoria = produto.subcategoriaId
    else:
        document_id = produto.get("$id") or produto.get("id")
        codigo_barras = produto.get("codigo_barras", "")
        codigo_interno = produto.get("codigo_interno")
        nome = produto.get("nome", "")
        descricao = produto.get("descricao")
        preco_consumidor = produto.get("preco_consumidor", 0.0)
        preco_fabrica = produto.get("preco_fabrica")
        pmc = produto.get("pmc")
        desconto_comercial = produto.get("desconto_comercial")
        valor_substituicao_tributaria = produto.get("valor_substituicao_tributaria")
        preco_nf = produto.get("preco_nf")
        collection_id = (
            produto.get("$collectionId")
            or produto.get("collectionId")
            or produto.get("collection_id")
        )
        laboratorio = produto.get("laboratorioId") or produto.get("laboratorio")
        categoria = produto.get("categoriaId") or produto.get("categoria")
        lab_nome = produto.get("lab_nome")
        cat_nome = produto.get("cat_nome")
        subcategoria = produto.get("subcategoriaId") or produto.get("subcategoria")

    return ProdutoCatalogoPublicOut(
        id=document_id,
        codigo_ean=codigo_barras,
        codigo_interno=codigo_interno,
        nome=nome,
        descricao=descricao,
        preco_base=preco_consumidor,
        preco_fabrica=preco_fabrica,
        pmc=pmc,
        desconto_comercial=desconto_comercial,
        valor_substituicao_tributaria=valor_substituicao_tributaria,
        preco_nf=preco_nf,
        collection_id=collection_id,
        laboratorio=laboratorio,
        categoria=categoria,
        lab_nome=lab_nome,
        cat_nome=cat_nome,
        subcategoria=subcategoria,
    )


@router.post(
    "",
    summary="Criar produto de catálogo",
    description="Cria um novo produto de catálogo garantindo unicidade do código de barras.",
    response_model=ProdutoCatalogoAppwriteDocument,
    status_code=status.HTTP_201_CREATED,
    responses={
        status.HTTP_201_CREATED: {
            "description": "Produto criado",
            "content": {
                "application/json": {
                    "example": {
                        "codigo_ean": "7891234523190",
                        "codigo_interno": "12345-XYZ",
                        "nome": "Produto Exemplo2",
                        "descricao": "Descrição do produto com detalhes importantes.",
                        "preco_base": 100,
                        "preco_fabrica": 80,
                        "pmc": 120,
                        "desconto_comercial": 10,
                        "valor_substituicao_tributaria": 5,
                        "preco_nf": 95,
                        "$id": "68e806a9f3a1ba1fc463",
                        "$permissions": [
                            "read(\"user:68c06f65003a3978ebee\")",
                            "update(\"user:68c06f65003a3978ebee\")",
                            "delete(\"user:68c06f65003a3978ebee\")",
                        ],
                        "$createdAt": "2025-10-09T19:02:02.001+00:00",
                        "$updatedAt": "2025-10-09T19:02:02.001+00:00",
                        "$sequence": 38,
                        "laboratorio": {
                            "nome": "teuto",
                            "$id": "68c8856a6ad78aa96494",
                            "$sequence": 1,
                            "$createdAt": "2025-09-15T21:30:18.438+00:00",
                            "$updatedAt": "2025-09-15T21:30:18.438+00:00",
                            "$permissions": [],
                            "$databaseId": "saveinmed",
                            "$collectionId": "laboratorios",
                        },
                        "categoria": {
                            "$databaseId": "saveinmed",
                            "$collectionId": "categorias",
                            "$sequence": 0,
                        },
                        "lab_nome": "EMS",
                        "cat_nome": "Medicamento",
                        "$databaseId": "saveinmed",
                        "$collectionId": "produtos-catalogo",
                    }
                }
            },
        },
        status.HTTP_409_CONFLICT: {
            "description": "Código de barras duplicado",
            "content": {"application/json": {"example": {"detail": "Barcode already exists"}}},
        },
        status.HTTP_404_NOT_FOUND: {
            "description": "Relação não encontrada",
            "content": {
                "application/json": {
                    "example": {"detail": "Categoria não encontrada"}
                }
            },
        },
    },
)
async def create_produto_catalogo(
    payload: ProdutoCatalogoCreateRequest,
    _: None = Depends(require_api_key),
    service: ProdutosCatalogoService = Depends(get_produtos_catalogo_service),
) -> ProdutoCatalogoAppwriteDocument:
    return await service.create(payload)


@router.patch(
    "/{produto_id}",
    summary="Atualizar produto de catálogo",
    description="Atualiza parcialmente um produto de catálogo garantindo validações das relações e unicidade.",
    response_model=ProdutoCatalogoAppwriteDocument,
    responses={
        status.HTTP_200_OK: {
            "description": "Produto atualizado",
            "content": {
                "application/json": {
                    "example": {
                        "codigo_ean": "7891234523190",
                        "codigo_interno": "12345-XYZ",
                        "nome": "Produto Exemplo2",
                        "descricao": "Descrição do produto com detalhes importantes.",
                        "preco_base": 100,
                        "preco_fabrica": 80,
                        "pmc": 120,
                        "desconto_comercial": 10,
                        "valor_substituicao_tributaria": 5,
                        "preco_nf": 95,
                        "$id": "68e806a9f3a1ba1fc463",
                        "$permissions": [
                            "read(\"user:68c06f65003a3978ebee\")",
                            "update(\"user:68c06f65003a3978ebee\")",
                            "delete(\"user:68c06f65003a3978ebee\")",
                        ],
                        "$createdAt": "2025-10-09T19:02:02.001+00:00",
                        "$updatedAt": "2025-10-09T19:02:02.001+00:00",
                        "$sequence": 38,
                        "laboratorio": {
                            "nome": "teuto",
                            "$id": "68c8856a6ad78aa96494",
                            "$sequence": 1,
                            "$createdAt": "2025-09-15T21:30:18.438+00:00",
                            "$updatedAt": "2025-09-15T21:30:18.438+00:00",
                            "$permissions": [],
                            "$databaseId": "saveinmed",
                            "$collectionId": "laboratorios",
                        },
                        "categoria": {
                            "$databaseId": "saveinmed",
                            "$collectionId": "categorias",
                            "$sequence": 0,
                        },
                        "lab_nome": "EMS",
                        "cat_nome": "Medicamento",
                        "$databaseId": "saveinmed",
                        "$collectionId": "produtos-catalogo",
                    }
                }
            },
        },
        status.HTTP_404_NOT_FOUND: {
            "description": "Produto não encontrado",
            "content": {
                "application/json": {
                    "example": {"detail": "Produto catálogo não encontrado."}
                }
            },
        },
        status.HTTP_409_CONFLICT: {
            "description": "Código de barras duplicado",
            "content": {"application/json": {"example": {"detail": "Barcode already exists"}}},
        },
    },
)
async def update_produto_catalogo(
    produto_id: str,
    payload: ProdutoCatalogoUpdateRequest,
    _: None = Depends(require_api_key),
    service: ProdutosCatalogoService = Depends(get_produtos_catalogo_service),
) -> ProdutoCatalogoAppwriteDocument:
    return await service.update(produto_id, payload)


@router.delete(
    "/{produto_id}",
    summary="Remover produto de catálogo",
    description="Exclui um produto de catálogo, respeitando as restrições de relacionamento configuradas.",
    status_code=status.HTTP_204_NO_CONTENT,
    responses={
        status.HTTP_204_NO_CONTENT: {"description": "Produto removido"},
        status.HTTP_404_NOT_FOUND: {
            "description": "Produto não encontrado",
            "content": {
                "application/json": {
                    "example": {"detail": "Produto catálogo não encontrado."}
                }
            },
        },
        status.HTTP_409_CONFLICT: {
            "description": "Restrição de relacionamento violada",
            "content": {
                "application/json": {
                    "example": {"detail": "Operation not permitted."}
                }
            },
        },
    },
)
async def delete_produto_catalogo(
    produto_id: str,
    _: None = Depends(require_api_key),
    service: ProdutosCatalogoService = Depends(get_produtos_catalogo_service),
) -> None:
    await service.delete(produto_id)
