"""Autenticação local (SQLite + bcrypt), sessão e proteção CSRF."""
from __future__ import annotations

import functools
import hmac
import secrets

import bcrypt
from flask import (
    Blueprint,
    abort,
    redirect,
    render_template,
    request,
    session,
    url_for,
)

from . import audit
from .db import get_db

bp = Blueprint("auth", __name__)


def hash_password(raw: str) -> str:
    return bcrypt.hashpw(raw.encode("utf-8"), bcrypt.gensalt()).decode("utf-8")


def check_password(raw: str, hashed: str) -> bool:
    try:
        return bcrypt.checkpw(raw.encode("utf-8"), hashed.encode("utf-8"))
    except (ValueError, TypeError):
        return False


def csrf_token() -> str:
    if "csrf" not in session:
        session["csrf"] = secrets.token_urlsafe(32)
    return session["csrf"]


def verify_csrf():
    if request.method in ("GET", "HEAD", "OPTIONS"):
        return None
    sent = request.form.get("csrf_token") or request.headers.get("X-CSRF-Token", "")
    expected = session.get("csrf", "")
    if not expected or not hmac.compare_digest(sent, expected):
        abort(400, "Token CSRF inválido. Recarregue a página e tente novamente.")
    return None


def login_required(view):
    @functools.wraps(view)
    def wrapper(*args, **kwargs):
        if not session.get("user_id"):
            return redirect(url_for("auth.login", next=request.path))
        return view(*args, **kwargs)

    return wrapper


@bp.route("/login", methods=["GET", "POST"])
def login():
    error = None
    if request.method == "POST":
        username = (request.form.get("username") or "").strip()
        password = request.form.get("password") or ""
        row = get_db().execute(
            "SELECT * FROM users WHERE username = ? AND active = 1", (username,)
        ).fetchone()
        if row and check_password(password, row["password_hash"]):
            session.clear()
            session["user_id"] = row["id"]
            session["username"] = row["username"]
            session["role"] = row["role"]
            csrf_token()
            db = get_db()
            db.execute(
                "UPDATE users SET last_login = datetime('now') WHERE id = ?", (row["id"],)
            )
            db.commit()
            audit.log("login", "Acesso ao painel autorizado", username=row["username"])
            nxt = request.args.get("next") or url_for("dashboard.index")
            return redirect(nxt if nxt.startswith("/") else url_for("dashboard.index"))
        error = "Usuário ou senha inválidos."
        audit.log("login_falhou", f"Tentativa para usuário '{username}'", username=username or "-")
    return render_template("login.html", error=error), (401 if error else 200)


@bp.post("/logout")
@login_required
def logout():
    audit.log("logout", "Sessão encerrada")
    session.clear()
    return redirect(url_for("auth.login"))
