"""
SISTEMA DE ALMOXARIFADO - FastAPI (VERSÃO SIMPLIFICADA)
Sem passlib/bcrypt, senha checada em texto puro
"""

from fastapi import FastAPI, Request, UploadFile, File, Depends, HTTPException, Form
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from typing import Optional
import pandas as pd
import os
import aiofiles
import uuid

app = FastAPI(title="Sistema de Almoxarifado", version="1.0.0")

# Montar pastas estáticas e templates
BASE_DIR = os.path.dirname(os.path.abspath(__file__))

static_dir = os.path.join(BASE_DIR, "static")
templates_dir = os.path.join(BASE_DIR, "templates")
uploads_dir = os.path.join(static_dir, "uploads")

os.makedirs(uploads_dir, exist_ok=True)

app.mount("/static", StaticFiles(directory=static_dir), name="static")
templates = Jinja2Templates(directory=templates_dir)

# Segurança simples (sem hash)
security = HTTPBearer()

# "Banco" de usuários em memória - senha em texto puro
USERS_DB = {
    "UHESM": {
        "username": "UHESM",
        "password": "4820_4821",  # texto puro
        "role": "UHESM",
        "name": "Administrador",
    },
    "GHSM": {
        "username": "GHSM",
        "password": "4821",
        "role": "GHSM",
        "name": "Operador de Almoxarifado",
    },
}

# Arquivo da planilha
PLANILHA_FILE = os.path.join(uploads_dir, "almoxarifado_data.xlsx")


def get_user(username: str):
    return USERS_DB.get(username)


def is_admin(user: dict) -> bool:
    # Apenas UHESM é admin
    return user.get("username") == "UHESM"


async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
    """
    Token = username simples (vindo do /api/login)
    """
    username = credentials.credentials
    user = get_user(username)
    if not user:
        raise HTTPException(status_code=401, detail="Usuário não encontrado ou token inválido")
    return user


# ------------------ ROTAS HTML ------------------ #


@app.get("/", response_class=HTMLResponse)
async def tela_abertura(request: Request):
    return templates.TemplateResponse("tela_abertura.html", {"request": request})


@app.get("/home", response_class=HTMLResponse)
async def home(request: Request):
    return templates.TemplateResponse("home.html", {"request": request})


@app.get("/login", response_class=HTMLResponse)
async def login_page(request: Request):
    return templates.TemplateResponse("login.html", {"request": request})


@app.get("/dashboard", response_class=HTMLResponse)
async def dashboard(request: Request):
    """
    Tela HTML do dashboard.
    Proteção real (admin x operador):
      - front-end usando auth_token no localStorage
      - APIs (/api/...) via Depends(security) + is_admin
    """
    user = {"name": "Usuário", "role": "logado"}

    total_items = 0
    total_quantidade = 0
    depositos: list[str] = []

    return templates.TemplateResponse(
        "dashboard.html",
        {
            "request": request,
            "user": user,
            "total_items": total_items,
            "total_quantidade": total_quantidade,
            "depositos": depositos,
        },
    )


@app.get("/busca", response_class=HTMLResponse)
async def pagina_busca(request: Request):
    user = {"name": "Usuário", "role": "logado"}
    return templates.TemplateResponse("busca.html", {"request": request, "user": user})


@app.get("/logout")
async def logout():
    return RedirectResponse(url="/", status_code=303)


# ------------------ APIs ------------------ #


@app.post("/api/login")
async def api_login(
    username: str = Form(...),
    password: str = Form(...),
):
    user = get_user(username)
    if not user:
        return JSONResponse(status_code=401, content={"success": False, "message": "Usuário ou senha inválidos"})

    if password != user["password"]:
        return JSONResponse(status_code=401, content={"success": False, "message": "Usuário ou senha inválidos"})

    # Token simples = username
    token = username
    return {
        "success": True,
        "token": token,
        "user": {"username": username, "name": user["name"], "role": user["role"]},
    }


@app.post("/api/buscar")
async def api_buscar(
    material: Optional[str] = None,
    descricao: Optional[str] = None,
    credentials: HTTPAuthorizationCredentials = Depends(security),
):
    _ = await get_current_user(credentials)

    if not os.path.exists(PLANILHA_FILE):
        return {"success": False, "message": "Planilha não encontrado"}

    try:
        df = pd.read_excel(PLANILHA_FILE)
        df.columns = [c.strip().upper() for c in df.columns]

        # Filtros
        if material and "MATERIAL" in df.columns:
            df = df[df["MATERIAL"].astype(str).str.contains(material, case=False, na=False)]
        if descricao and "DESCRICAO" in df.columns:
            df = df[df["DESCRICAO"].astype(str).str.contains(descricao, case=False, na=False)]

        # Trocar NaN por string vazia
        df = df.fillna("")

        # Garantir que FOTO é string pura (sem "nan")
        if "FOTO" in df.columns:
            df.loc[:, "FOTO"] = df["FOTO"].astype(str).str.replace("nan", "", regex=False)

        resultados = df.to_dict(orient="records")

        return {"success": True, "total": len(resultados), "resultados": resultados}
    except Exception as e:
        return {"success": False, "message": f"Erro ao buscar: {e}"}


@app.get("/api/sugestoes")
async def api_sugestoes(
    termo: str,
    campo: str = "DESCRICAO",
    limit: int = 10,
    credentials: HTTPAuthorizationCredentials = Depends(security),
):
    _ = await get_current_user(credentials)

    if not os.path.exists(PLANILHA_FILE):
        return {"success": False, "sugestoes": []}

    try:
        df = pd.read_excel(PLANILHA_FILE)
        df.columns = [c.strip().upper() for c in df.columns]

        campo = campo.strip().upper()
        if campo not in df.columns:
            return {"success": False, "sugestoes": []}

        termo = termo.strip()
        if len(termo) < 3:
            return {"success": True, "sugestoes": []}

        serie = df[campo].dropna().astype(str)
        mask = serie.str.contains(termo, case=False, na=False)
        sugestoes = serie[mask].unique().tolist()
        sugestoes = sugestoes[:limit]

        return {"success": True, "sugestoes": sugestoes}
    except Exception as e:
        return {"success": False, "sugestoes": [], "error": str(e)}


@app.post("/api/upload-planilha")
async def upload_planilha(
    file: UploadFile = File(...),
    credentials: HTTPAuthorizationCredentials = Depends(security),
):
    user = await get_current_user(credentials)
    if not is_admin(user):
        raise HTTPException(status_code=403, detail="Apenas admin pode atualizar a planilha")

    if not (file.filename.endswith(".xlsx") or file.filename.endswith(".xls")):
        raise HTTPException(status_code=400, detail="Arquivo deve ser Excel (.xlsx ou .xls)")


    os.makedirs(uploads_dir, exist_ok=True)
    save_path = PLANILHA_FILE

    async with aiofiles.open(save_path, "wb") as out_file:
        content = await file.read()
        await out_file.write(content)

    return {"success": True, "message": f"Planilha atualizada com sucesso! Arquivo: {file.filename}"}


@app.post("/api/upload-foto-item")
async def upload_foto_item(
    material: str = Form(...),
    file: UploadFile = File(...),
    credentials: HTTPAuthorizationCredentials = Depends(security),
):
    user = await get_current_user(credentials)
    if not is_admin(user):
        raise HTTPException(status_code=403, detail="Apenas admin pode enviar fotos")

    if not os.path.exists(PLANILHA_FILE):
        raise HTTPException(status_code=400, detail="Planilha não encontrada")

    if not file.filename.lower().endswith((".png", ".jpg", ".jpeg", ".gif")):
        raise HTTPException(status_code=400, detail="Arquivo deve ser uma imagem (png, jpg, jpeg, gif)")


    # Salvar imagem
    ext = os.path.splitext(file.filename)[1].lower()
    nome_arquivo = f"{uuid.uuid4().hex}{ext}"
    images_dir = os.path.join(static_dir, "images")
    os.makedirs(images_dir, exist_ok=True)
    caminho_arquivo = os.path.join(images_dir, nome_arquivo)

    async with aiofiles.open(caminho_arquivo, "wb") as out_file:
        content = await file.read()
        await out_file.write(content)

    url_relativa = f"/static/images/{nome_arquivo}"

    # Ler planilha
    df = pd.read_excel(PLANILHA_FILE)
    df.columns = [c.strip().upper() for c in df.columns]

    if "MATERIAL" not in df.columns:
        raise HTTPException(status_code=400, detail="Coluna MATERIAL não encontrada na planilha")

    if "FOTO" not in df.columns:
        df["FOTO"] = ""

    # Normalizar MATERIAL (remove espaços, .0 e ignora maiúscula/minúscula)
    material_input = material.strip().upper()

    df["MATERIAL_STR"] = df["MATERIAL"].astype(str).str.strip()
    df["MATERIAL_STR"] = df["MATERIAL_STR"].str.replace(r"\.0$", "", regex=True)
    df["MATERIAL_NORMALIZED"] = df["MATERIAL_STR"].str.upper()

    mask = df["MATERIAL_NORMALIZED"] == material_input

    if not mask.any():
        materiais_disponiveis = df["MATERIAL_STR"].unique().tolist()[:10]
        dica = "Materiais disponíveis: " + ", ".join([str(m) for m in materiais_disponiveis])
        raise HTTPException(
            status_code=404,
            detail=f"Material '{material}' não encontrado na planilha. {dica}",
        )

    # Atualizar FOTO na linha encontrada
    df.loc[mask, "FOTO"] = url_relativa

    # Remover colunas auxiliares
    for col in ["MATERIAL_STR", "MATERIAL_NORMALIZED"]:
        if col in df.columns:
            df.drop(columns=[col], inplace=True)

    # Salvar planilha
    df.to_excel(PLANILHA_FILE, index=False)

    return {"success": True, "message": "Foto atualizada com sucesso", "url_foto": url_relativa}


@app.get("/api/planilha-info")
async def get_planilha_info(credentials: HTTPAuthorizationCredentials = Depends(security)):
    _ = await get_current_user(credentials)

    if not os.path.exists(PLANILHA_FILE):
        return {"exists": False, "message": "Nenhuma planilha carregada"}

    try:
        df = pd.read_excel(PLANILHA_FILE)
        colunas = df.columns.tolist()
        total_registros = len(df)
        df_amostra = df.head(5).fillna("").copy()
        if "FOTO" in df_amostra.columns:
            df_amostra.loc[:, "FOTO"] = df_amostra["FOTO"].astype(str).str.replace("nan", "", regex=False)
        return {
            "exists": True,
            "total_registros": int(total_registros),
            "colunas": colunas,
            "amostra": df_amostra.to_dict(orient="records"),
        }
    except Exception as e:
        return {"exists": False, "error": str(e)}


if __name__ == "__main__":
    import uvicorn

    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)