from fastapi import APIRouter, Depends, HTTPException, Request, Response
from sqlalchemy.orm import Session
from starlette.concurrency import run_in_threadpool

from custos_precificacao import auth, importacao
from custos_precificacao.api.deps import get_session
from custos_precificacao.api.schemas import AbaImportacaoOut, ErroImportacaoOut, ResultadoImportacaoOut
from custos_precificacao.importacao_modelo import gerar_modelo

router = APIRouter(prefix="/importacao", tags=["importacao"], dependencies=[Depends(auth.exigir_admin)])

XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
ERROS_POR_ABA = 100  # a resposta traz as primeiras ocorrências; `n_erros` tem o total


def _saida(resultado: importacao.Resultado) -> ResultadoImportacaoOut:
    return ResultadoImportacaoOut(
        ok=resultado.ok,
        gravado=resultado.gravado,
        n_erros=resultado.n_erros,
        erros_gerais=resultado.erros_gerais,
        abas=[
            AbaImportacaoOut(
                nome=a.nome, lidas=a.lidas, criados=a.criados, atualizados=a.atualizados, iguais=a.iguais,
                n_erros=len(a.erros),
                erros=[ErroImportacaoOut(linha=e.linha, coluna=e.coluna, mensagem=e.mensagem) for e in a.erros[:ERROS_POR_ABA]],
            )
            for a in resultado.abas
        ],
    )


async def _corpo(request: Request) -> bytes:
    tamanho = request.headers.get("content-length")
    if tamanho and tamanho.isdigit() and int(tamanho) > importacao.LIMITE_BYTES:
        raise HTTPException(status_code=413, detail=f"Arquivo grande demais; o limite é {importacao.LIMITE_BYTES // 1024 // 1024} MB")
    dados = await request.body()
    if not dados:
        raise HTTPException(status_code=422, detail="Nenhum arquivo foi enviado")
    return dados


@router.get("/modelo")
def baixar_modelo(preenchido: bool = False, session: Session = Depends(get_session)) -> Response:
    """Modelo .xlsx para preencher (a aba Referência traz o Plano de Contas e as Atividades atuais). Com `preenchido=true`,
    as abas de cadastro de custeio vêm com os registros atuais do Planejamento, para editar e subir de volta."""
    nome = "custeio_geral_preenchido.xlsx" if preenchido else "modelo_importacao.xlsx"
    return Response(
        content=gerar_modelo(session, preenchido=preenchido), media_type=XLSX,
        headers={"Content-Disposition": f'attachment; filename="{nome}"'},
    )


@router.post("/previa", response_model=ResultadoImportacaoOut)
async def previa(request: Request, session: Session = Depends(get_session)) -> ResultadoImportacaoOut:
    """Valida a planilha e mostra o que seria criado/atualizado e os erros — sem gravar nada."""
    dados = await _corpo(request)
    return _saida(await run_in_threadpool(importacao.importar, session, dados, gravar=False))


@router.post("/confirmar", response_model=ResultadoImportacaoOut)
async def confirmar(request: Request, session: Session = Depends(get_session)) -> ResultadoImportacaoOut:
    """Revalida e grava, tudo ou nada: se houver qualquer erro, nada é gravado."""
    dados = await _corpo(request)
    return _saida(await run_in_threadpool(importacao.importar, session, dados, gravar=True))
