"""DNS Shield ISP - fábrica da aplicação Flask.

Desenvolvedor: Euquias Junior <junior@jbinfo.com.br>
"""
import logging
import os
from datetime import datetime
from logging.handlers import RotatingFileHandler
from pathlib import Path

from flask import Flask, g, render_template, session

from .config import get_config, APP_VERSION
from .db import init_app_db, get_provider

__all__ = ["create_app", "APP_VERSION"]

LOG_DIR = Path(os.environ.get("DNSSHIELD_LOG_DIR", "/var/log/dnsshield"))


def _setup_logging(app: Flask) -> None:
    """Traceback completo no journal (stderr) e em /var/log/dnsshield/app.log."""
    fmt = logging.Formatter("%(asctime)s %(levelname)s [%(name)s] %(message)s")

    stream = logging.StreamHandler()
    stream.setFormatter(fmt)
    app.logger.addHandler(stream)

    try:
        LOG_DIR.mkdir(parents=True, exist_ok=True)
        file_handler = RotatingFileHandler(
            LOG_DIR / "app.log", maxBytes=2 * 1024 * 1024, backupCount=5, encoding="utf-8"
        )
        file_handler.setFormatter(fmt)
        app.logger.addHandler(file_handler)
    except OSError as exc:  # diretório sem permissão: segue apenas com o journal
        app.logger.warning("Log em arquivo desabilitado (%s): %s", LOG_DIR, exc)

    app.logger.setLevel(logging.INFO)
    app.logger.propagate = False


def create_app() -> Flask:
    cfg = get_config()

    app = Flask(
        __name__,
        template_folder="../templates",
        static_folder="../static",
    )
    app.config["SECRET_KEY"] = cfg.secret_key
    app.config["MAX_CONTENT_LENGTH"] = 8 * 1024 * 1024  # 8 MB (importação em massa)
    app.config["SESSION_COOKIE_HTTPONLY"] = True
    app.config["SESSION_COOKIE_SAMESITE"] = "Lax"
    app.config["DNSSHIELD"] = cfg

    _setup_logging(app)
    init_app_db(app)

    from .auth import bp as auth_bp, csrf_token, verify_csrf
    from .routes.dashboard import bp as dashboard_bp
    from .routes.blocks import bp as blocks_bp
    from .routes.exceptions import bp as exceptions_bp
    from .routes.anablock import bp as anablock_bp
    from .routes.federacao import bp as federacao_bp, api as federacao_api_bp
    from .routes.licenca import bp as licenca_bp
    from .routes.settings import bp as settings_bp
    from .routes.logs import bp as logs_bp
    from .routes.update import bp as update_bp

    for bp in (
        auth_bp,
        dashboard_bp,
        blocks_bp,
        exceptions_bp,
        anablock_bp,
        federacao_bp,
        federacao_api_bp,
        licenca_bp,
        settings_bp,
        logs_bp,
        update_bp,
    ):
        app.register_blueprint(bp)


    @app.before_request
    def _csrf_guard():
        return verify_csrf()

    @app.context_processor
    def _inject_globals():
        from . import licenca as licenca_mod

        try:
            licenca_estado = licenca_mod.estado()
        except Exception:  # noqa: BLE001 - banco ainda não migrado
            licenca_estado = {"autorizado": False, "modulos_ativos": [], "motivo": ""}

        return {
            "licenca": licenca_estado,
            "modulo_liberado": lambda m: m in licenca_estado.get("modulos_ativos", []),
            "app_version": APP_VERSION,
            "current_user": session.get("username"),
            "provider": get_provider(),
            "csrf_token": csrf_token,
            "dev_name": "Euquias Junior",
            "dev_email": "junior@jbinfo.com.br",
        }

    @app.errorhandler(Exception)
    def _handle_unexpected(exc):
        from werkzeug.exceptions import HTTPException

        if isinstance(exc, HTTPException):
            return exc
        momento = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
        app.logger.exception("Erro nao tratado em %s (%s)", request_path(), momento)
        return render_template("error.html", momento=momento, log_dir=str(LOG_DIR)), 500

    @app.teardown_appcontext
    def _close_db(_exc=None):
        conn = g.pop("db", None)
        if conn is not None:
            conn.close()

    return app


def request_path() -> str:
    from flask import request

    try:
        return f"{request.method} {request.path}"
    except RuntimeError:
        return "-"
