"""Inicialização do ambiente de produção (cPanel/Passenger): validação do ambiente, migrations,
cadastros estruturais e primeiro administrador. Tudo idempotente — roda a cada partida do app.

Variáveis (definidas no cPanel, "Setup Python App"):
- `APP_ENV=prod`, `DATABASE_URL`, `SECRET_KEY` (≥ 32 caracteres): obrigatórias em produção.
- `AUTO_MIGRATE=1`: aplica `alembic upgrade head`, semeia os cadastros estruturais num banco vazio e
  cria o primeiro administrador (abaixo).
- `BOOTSTRAP_ADMIN_EMAIL` / `BOOTSTRAP_ADMIN_SENHA`: usados só se ainda não existe nenhum usuário.
"""

import logging
import os
from pathlib import Path

from sqlalchemy import text

from custos_precificacao import config

log = logging.getLogger("custos_precificacao.producao")

RAIZ = Path(__file__).resolve().parents[2]  # pasta que contém src/, migrations/ e alembic.ini
_LOCK_ID = 727274  # advisory lock do Postgres: várias workers do Passenger não migram ao mesmo tempo


def validar_ambiente() -> None:
    """Em produção, recusa subir com configuração insegura ou incompleta."""
    if not config.em_producao():
        return
    faltando = [nome for nome in ("DATABASE_URL", "SECRET_KEY") if not os.getenv(nome, "").strip()]
    if faltando:
        raise RuntimeError(f"Variáveis de ambiente obrigatórias em produção: {', '.join(faltando)}")
    from custos_precificacao import auth

    auth.chave_secreta()  # confere o tamanho mínimo
    if os.getenv("AUTH_DESLIGADA", "").strip() == "1":
        raise RuntimeError("AUTH_DESLIGADA=1 não pode ser usada em produção; remova a variável")
    if not config.cookie_seguro():
        log.warning("COOKIE_SECURE não está ligado: o cookie de sessão pode trafegar sem HTTPS")


def migrar(url: str | None = None) -> None:
    from alembic import command
    from alembic.config import Config

    cfg = Config()
    cfg.set_main_option("script_location", str(RAIZ / "migrations"))
    cfg.set_main_option("prepend_sys_path", str(RAIZ / "src"))
    if url:
        cfg.attributes["url"] = url
    command.upgrade(cfg, "head")


def semear_se_vazio(session) -> bool:
    """Num banco novo (Plano de Contas vazio) cria os cadastros estruturais. Devolve se semeou."""
    from custos_precificacao.models import PlanoDeContas
    from custos_precificacao.seeds import semear_dicionario_processos, semear_plano_de_contas

    if session.query(PlanoDeContas).first() is not None:
        return False
    semear_plano_de_contas(session)
    semear_dicionario_processos(session)
    session.commit()
    return True


def garantir_contas_dos_gastos(session) -> int:
    """Cria, se faltarem, as contas dos campos fixos de "Alterar gastos" (Funcionário, Máquina, Ambiente) — assim bancos antigos
    ganham as contas novas no deploy e a importação por planilha já as encontra. Idempotente. Devolve quantas criou."""
    from custos_precificacao import folha, plano_padrao

    criadas = folha.garantir_todas_as_contas(session)
    criadas += plano_padrao.garantir_conta(session, "PC-IMP-CBS")[1]  # a DRE primária lança a CBS nesta conta
    if criadas:
        session.commit()
    return criadas


def criar_admin_inicial(session) -> bool:
    """Cria o primeiro administrador a partir das variáveis, se ainda não há nenhum usuário."""
    from custos_precificacao import auth
    from custos_precificacao.models import Usuario

    email = os.getenv("BOOTSTRAP_ADMIN_EMAIL", "").strip()
    senha = os.getenv("BOOTSTRAP_ADMIN_SENHA", "")
    if not email or not senha or session.query(Usuario).first() is not None:
        return False
    try:
        auth.criar_usuario(session, email, os.getenv("BOOTSTRAP_ADMIN_NOME", "Administrador"), senha, admin=True)
    except ValueError as exc:  # não derruba o site: o erro aparece no log e o admin pode corrigir a variável
        session.rollback()
        log.error("Não foi possível criar o administrador inicial: %s", exc)
        return False
    session.commit()
    log.warning("Administrador inicial criado (%s). Remova BOOTSTRAP_ADMIN_SENHA das variáveis.", email)
    return True


def inicializar() -> None:
    """Ponto de entrada do `passenger_wsgi.py`: valida o ambiente e, com `AUTO_MIGRATE=1`, prepara o banco."""
    validar_ambiente()
    if os.getenv("AUTO_MIGRATE", "").strip() != "1":
        return
    from custos_precificacao.db import SessionLocal, engine

    with engine.connect() as trava:
        postgres = engine.dialect.name == "postgresql"
        if postgres:
            trava.execute(text("select pg_advisory_lock(:id)"), {"id": _LOCK_ID})
        try:
            migrar()
            from custos_precificacao import planejamento_copia
            from custos_precificacao.api.deps import rotear_para_planejamento

            for codigo in planejamento_copia.separar_legados(engine):
                log.warning("Planejamento %s ganhou o seu próprio schema (dados separados dos demais)", codigo)
            with SessionLocal() as session:
                rotear_para_planejamento(session, None)  # os cadastros ficam no Planejamento padrão
                semear_se_vazio(session)
                garantir_contas_dos_gastos(session)
                criar_admin_inicial(session)
        finally:
            if postgres:
                trava.execute(text("select pg_advisory_unlock(:id)"), {"id": _LOCK_ID})
                trava.commit()
