from __future__ import annotations

from typing import Any

import pandas as pd
import structlog

from agrobr.exceptions import ParseError
from agrobr.utils.geo import check_geopandas, parse_geojson_base
from agrobr.utils.io import concat_csv_pages

from .models import COLUNAS_SAIDA, COLUNAS_SAIDA_GEO, MAX_FEATURES_GEO, RENAME_MAP

logger = structlog.get_logger()

PARSER_VERSION = 1

_REQUIRED_COLS_RAW = {"numero_tad", "data_tad", "sig_uf", "qtd_area_desmatada"}


def parse_embargos_csv(pages: list[bytes]) -> pd.DataFrame:
    df = concat_csv_pages(
        pages,
        source="ibama",
        parser_version=PARSER_VERSION,
        empty_columns=COLUNAS_SAIDA,
    )
    if df.empty:
        return df

    missing = _REQUIRED_COLS_RAW - set(df.columns)
    if missing:
        raise ParseError(
            source="ibama",
            parser_version=PARSER_VERSION,
            reason=f"Colunas obrigatorias ausentes: {missing}",
        )

    df = df.rename(columns=RENAME_MAP)

    df["data_embargo"] = pd.to_datetime(df["data_embargo"], errors="coerce")
    df["area_desmatada_ha"] = pd.to_numeric(df["area_desmatada_ha"], errors="coerce")
    df["uf"] = df["uf"].fillna("").str.strip().str.upper()
    if "municipio" in df.columns:
        df["municipio"] = df["municipio"].fillna("").str.strip()

    output_cols = [c for c in COLUNAS_SAIDA if c in df.columns]
    df = df[output_cols].reset_index(drop=True)

    logger.info("ibama_embargos_parse_ok", records=len(df))
    return df


def parse_embargos_geojson(data: bytes) -> Any:
    gpd = check_geopandas()
    gdf = parse_geojson_base(
        data,
        gpd,
        source="ibama",
        parser_version=PARSER_VERSION,
        required_cols=_REQUIRED_COLS_RAW,
        max_features=MAX_FEATURES_GEO,
        output_cols_empty=COLUNAS_SAIDA_GEO,
        truncation_event="ibama_embargos_geo_truncated",
        warn_null_geom=True,
    )
    if gdf.empty:
        return gdf

    gdf = gdf.rename(columns=RENAME_MAP)
    gdf["data_embargo"] = pd.to_datetime(gdf["data_embargo"], errors="coerce")
    gdf["area_desmatada_ha"] = pd.to_numeric(gdf["area_desmatada_ha"], errors="coerce")
    gdf["uf"] = gdf["uf"].fillna("").str.strip().str.upper()
    if "municipio" in gdf.columns:
        gdf["municipio"] = gdf["municipio"].fillna("").str.strip()

    output_cols = [c for c in COLUNAS_SAIDA_GEO if c in gdf.columns]
    return gdf[output_cols].reset_index(drop=True)
