"""Domínios liberados / exceções judiciais (passthrough RPZ)."""
from __future__ import annotations

import csv
import io
import sqlite3
from datetime import datetime

from flask import (
    Blueprint,
    Response,
    flash,
    redirect,
    render_template,
    request,
    session,
    url_for,
)

from .. import audit, rpz
from ..auth import login_required
from ..db import get_db

bp = Blueprint("exceptions", __name__, url_prefix="/liberacoes")

PER_PAGE = 50


def _sync_and_flash(context: str) -> None:
    try:
        rpz.sync_zone()
        flash("Zona RPZ regravada com as regras de passthrough.", "success")
    except rpz.RPZError as exc:
        flash(f"Alteração salva no banco, mas a zona não recarregou: {exc}", "error")
        audit.log("rpz_erro", f"{context}: {exc}")


@bp.get("/")
@login_required
def index():
    q = (request.args.get("q") or "").strip()
    page = max(int(request.args.get("page", 1) or 1), 1)

    where, params = ["active = 1"], []
    if q:
        where.append("domain LIKE ?")
        params.append(f"%{q.lower()}%")
    clause = " AND ".join(where)

    db = get_db()
    total = db.execute(
        f"SELECT COUNT(*) AS c FROM liberacoes WHERE {clause}", params
    ).fetchone()["c"]
    rows = db.execute(
        f"SELECT * FROM liberacoes WHERE {clause} ORDER BY id DESC LIMIT ? OFFSET ?",
        [*params, PER_PAGE, (page - 1) * PER_PAGE],
    ).fetchall()

    pages = max((total + PER_PAGE - 1) // PER_PAGE, 1)
    return render_template(
        "exceptions.html",
        rows=[dict(r) for r in rows],
        total=total,
        page=page,
        pages=pages,
        q=q,
    )


@bp.post("/adicionar")
@login_required
def add():
    raw_domain = request.form.get("domain") or ""
    processo = (request.form.get("processo") or "").strip()
    notes = (request.form.get("notes") or "").strip()

    domain = rpz.normalize_domain(raw_domain)
    if not domain:
        flash(f"Domínio inválido: '{raw_domain}'.", "error")
        return redirect(url_for("exceptions.index"))
    if not processo:
        flash("Informe o número do processo/ofício de liberação.", "error")
        return redirect(url_for("exceptions.index"))

    user = session.get("username", "-")
    db = get_db()
    try:
        db.execute(
            "INSERT INTO liberacoes (domain, processo, usuario, notes) VALUES (?, ?, ?, ?)",
            (domain, processo, user, notes),
        )
        db.commit()
        flash(f"Domínio '{domain}' liberado (passthrough).", "success")
    except sqlite3.IntegrityError:
        db.execute(
            "UPDATE liberacoes SET active = 1, processo = ?, usuario = ?, notes = ?, "
            "data_liberacao = datetime('now') WHERE domain = ?",
            (processo, user, notes, domain),
        )
        db.commit()
        flash(f"'{domain}' já constava e foi reativado com o novo processo.", "success")

    audit.log("liberacao_incluida", f"{domain} | processo {processo}")
    _sync_and_flash(f"liberação de {domain}")
    return redirect(url_for("exceptions.index"))


@bp.post("/remover/<int:free_id>")
@login_required
def remove(free_id: int):
    db = get_db()
    row = db.execute("SELECT * FROM liberacoes WHERE id = ?", (free_id,)).fetchone()
    if row is None:
        flash("Registro não encontrado.", "error")
        return redirect(url_for("exceptions.index"))
    db.execute("DELETE FROM liberacoes WHERE id = ?", (free_id,))
    db.commit()
    flash(
        f"Liberação de '{row['domain']}' removida. O domínio volta a seguir as "
        "regras de bloqueio, se houver.",
        "success",
    )
    audit.log("liberacao_removida", f"{row['domain']} | processo {row['processo']}")
    _sync_and_flash(f"remoção da liberação de {row['domain']}")
    return redirect(url_for("exceptions.index"))


@bp.get("/exportar.csv")
@login_required
def export_csv():
    rows = get_db().execute(
        "SELECT id, domain, processo, data_liberacao, usuario FROM liberacoes "
        "WHERE active = 1 ORDER BY id"
    ).fetchall()

    buffer = io.StringIO()
    writer = csv.writer(buffer, delimiter=";")
    writer.writerow(["ID", "Dominio", "Processo", "Data/Hora", "Usuario"])
    for r in rows:
        writer.writerow(
            [r["id"], r["domain"], r["processo"], r["data_liberacao"], r["usuario"]]
        )

    audit.log("exportacao_liberacoes", f"{len(rows)} registros exportados")
    filename = f"liberacoes-{datetime.now().strftime('%Y%m%d-%H%M%S')}.csv"
    return Response(
        "\ufeff" + buffer.getvalue(),
        mimetype="text/csv; charset=utf-8",
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )
