import logging
import json
import asyncio
from pathlib import Path

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from contextlib import asynccontextmanager

from .routes import router

logger = logging.getLogger(__name__)
from .config import settings
from .dependencies import es_client, oracle_client, ranking_oracle_repo, get_processar_job
from ...application.jobs.scheduler import RankingScheduler
from ...infrastructure.ranking_store import ranking_store, RankingEntry


async def carregar_ranking_do_oracle() -> int:
    if not ranking_oracle_repo or not oracle_client:
        logger.warning("Oracle não configurado - ranking será carregado do Elasticsearch quando solicitado")
        return 0

    try:
        if not oracle_client.is_connected:
            oracle_client.connect()
            if not oracle_client.is_connected:
                logger.warning("Não foi possível conectar ao Oracle")
                return 0

        def _sync_load():
            total = ranking_oracle_repo.contar_total()
            if total == 0:
                return []

            consultores = []
            batch_size = 10000
            total_pages = (total + batch_size - 1) // batch_size
            logger.info(f"Carregando {total} consultores do Oracle em {total_pages} batches...")

            for page in range(1, total_pages + 1):
                batch = ranking_oracle_repo.buscar_paginado(page=page, size=batch_size)
                consultores.extend(batch)

            return consultores

        consultores = await asyncio.wait_for(
            asyncio.get_event_loop().run_in_executor(None, _sync_load),
            timeout=300.0
        )

        if not consultores:
            logger.info("Nenhum dado encontrado no Oracle - ranking vazio")
            return 0

        entries = []
        for c in consultores:
            try:
                detalhes = json.loads(c.json_detalhes) if isinstance(c.json_detalhes, str) else c.json_detalhes or {}
            except (json.JSONDecodeError, TypeError, ValueError):
                detalhes = {}

            entries.append(
                RankingEntry(
                    id_pessoa=c.id_pessoa,
                    nome=c.nome,
                    posicao=c.posicao or 0,
                    pontuacao_total=int(c.pontuacao_total),
                    bloco_a=int(c.componente_a),
                    bloco_b=int(c.componente_b),
                    bloco_c=int(c.componente_c),
                    bloco_d=int(c.componente_d),
                    ativo=c.ativo,
                    anos_atuacao=float(c.anos_atuacao or 0),
                    detalhes=detalhes,
                )
            )

        await ranking_store.set_entries(entries)
        return len(entries)
    except asyncio.TimeoutError:
        logger.warning("Timeout ao carregar ranking do Oracle")
        return 0
    except Exception as e:
        logger.warning(f"Erro ao carregar ranking do Oracle: {e}")
        return 0


@asynccontextmanager
async def lifespan(app: FastAPI):
    await es_client.connect()

    try:
        if oracle_client:
            oracle_client.connect()
            if oracle_client.is_connected:
                logger.info("Conectado ao Oracle")
                total = await carregar_ranking_do_oracle()
                if total > 0:
                    logger.info(f"Ranking carregado do Oracle: {total} consultores")
                else:
                    logger.info("Ranking vazio no Oracle - aguardando processamento")
            else:
                logger.warning("Não foi possível conectar ao Oracle")
    except Exception as e:
        logger.warning(f"Erro ao inicializar Oracle: {e}")

    scheduler = None
    try:
        if settings.SCHEDULER_ENABLED:
            job = get_processar_job()
            scheduler = RankingScheduler(job)
            await scheduler.iniciar(hora_alvo=settings.SCHEDULER_HOUR)
    except Exception as e:
        logger.warning(f"Scheduler não iniciou: {e}")

    yield

    if scheduler:
        try:
            scheduler.parar()
        except Exception:
            pass

    if oracle_client:
        try:
            oracle_client.close()
        except Exception:
            pass

    await es_client.close()


app = FastAPI(
    title="Ranking de Consultores CAPES",
    description="Sistema de Ranking de Consultores CAPES baseado na Minuta Técnica",
    version="1.0.0",
    lifespan=lifespan,
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=False,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(router)

static_dir = Path(__file__).parent.parent.parent.parent / "static"
if static_dir.exists():
    app.mount("/api/static", StaticFiles(directory=str(static_dir)), name="static")


@app.get("/")
async def root():
    return {
        "message": "API Ranking CAPES",
        "version": "1.0.0",
        "docs": "/docs",
        "health": "/api/v1/health",
    }
