#!/usr/bin/env python
# -*- coding: utf-8 -*-
### DESEMBARQUE ÁREAS DE MANEJO (AMERBs)

import pandas as pd
from dash import Dash, dcc, html
from dash.dependencies import Input, Output
import plotly.express as px

TODAS_ESPECIES_VALUE = "__TODAS__"

# ============================
# 1) Leer base y normalizar
# ============================
df = pd.read_csv("data/AMERBS_1999_2024_clean.csv", low_memory=False)
df.columns = df.columns.str.strip()

rename_map = {
    "Año": "AÑO",
    "Mes": "MES",
    "Región": "REGION",
    "Código Caleta": "Cd_Caleta",
    "Caleta": "Nm_Caleta",
    "Area de Manejo": "AREA_MANEJO",
    "N° ROA": "N_ROA",
    "Cod Especie": "COD_ESPECIE",
    "Especie": "ESPECIE",
    "Kilos Des": "KILOS_DES",
    "Total Ton con humedad": "TOTAL_TON_HUM",
    "Organización": "ORGANIZACION",
}
df = df.rename(columns={k: v for k, v in rename_map.items() if k in df.columns})

df["ESPECIE"] = df["ESPECIE"].astype(str).str.upper().str.strip()
df["REGION"] = df["REGION"].astype(str).str.strip().str.replace(".0", "", regex=False)
df["AREA_MANEJO"] = df["AREA_MANEJO"].astype(str).str.strip()
df["Nm_Caleta"] = df["Nm_Caleta"].astype(str).str.strip()

# Año como entero real
df["AÑO"] = pd.to_numeric(df["AÑO"], errors="coerce").round().astype("Int64")
df["MES"] = pd.to_numeric(df["MES"], errors="coerce")
df["TOTAL_TON_HUM"] = pd.to_numeric(df["TOTAL_TON_HUM"], errors="coerce")

# ============================
# 2) Diccionario regiones
# ============================
dicc_regiones = {
    "15": "Arica y Parinacota (XV)",
    "1":  "Tarapacá (I)",
    "2":  "Antofagasta (II)",
    "3":  "Atacama (III)",
    "4":  "Coquimbo (IV)",
    "5":  "Valparaíso (V)",
    "6":  "Libertador General Bernardo O'Higgins (VI)",
    "7":  "Maule (VII)",
    "16": "Ñuble (XVI)",
    "8":  "Biobío (VIII)",
    "9":  "Araucanía (IX)",
    "14": "Los Ríos (XIV)",
    "10": "Los Lagos (X)",
    "11": "Aysén del General Carlos Ibáñez del Campo (XI)",
    "12": "Magallanes y Antártica Chilena (XII)",
    "13": "Región Metropolitana de Santiago (RM)",
}

df["REGION_NOMBRE"] = df["REGION"].map(dicc_regiones).fillna(df["REGION"])

# ============================
# 3) Base reducida
# ============================
df_base = df[
    ["ESPECIE", "AÑO", "TOTAL_TON_HUM", "REGION", "REGION_NOMBRE", "Nm_Caleta", "AREA_MANEJO"]
].dropna(subset=["AÑO", "TOTAL_TON_HUM"]).copy()

df_base["AÑO"] = df_base["AÑO"].astype(int)

min_year = int(df_base["AÑO"].min())
max_year = int(df_base["AÑO"].max())

especies_ordenadas = (
    df_base.groupby("ESPECIE")["TOTAL_TON_HUM"]
    .sum()
    .sort_values(ascending=False)
    .index.tolist()
)

especies_default_deseadas = ["LOCO", "LOCOS", "ERIZO ROJO", "ERIZO NEGRO"]
default_especies = [e for e in especies_default_deseadas if e in especies_ordenadas] or especies_ordenadas[:2]

region_order_geo = ["15", "1", "2", "3", "4", "5", "13", "6", "7", "16", "8", "9", "14", "10", "11", "12"]
regiones_presentes = sorted(df_base["REGION"].dropna().unique().tolist())
regiones_unicas = [r for r in region_order_geo if r in regiones_presentes]

map_region_nombre = {code: dicc_regiones.get(code, code) for code in regiones_unicas}

# ============================
# 3B) Metadata de AMERBs
# ============================
area_meta = (
    df_base.groupby("AREA_MANEJO", as_index=False)
    .agg({
        "REGION_NOMBRE": "first",
        "Nm_Caleta": "first"
    })
    .sort_values("AREA_MANEJO")
)

area_label_map = {
    row["AREA_MANEJO"]: f"{row['AREA_MANEJO']} ({row['REGION_NOMBRE']}, {row['Nm_Caleta']})"
    for _, row in area_meta.iterrows()
}

def build_area_options(dff):
    areas = (
        dff["AREA_MANEJO"]
        .dropna()
        .astype(str)
        .sort_values()
        .unique()
        .tolist()
    )
    return [{"label": area_label_map.get(a, a), "value": a} for a in areas]

def format_tons(x):
    return f"{x:,.1f} t".replace(",", "X").replace(".", ",").replace("X", ".")

def build_selected_areas_nodes(areas_sel):
    labels = [area_label_map.get(a, a) for a in areas_sel]
    nodes = []
    for i, label in enumerate(labels):
        if i > 0:
            nodes.append("; ")
        nodes.append(html.B(label))
    return nodes

def build_species_options(species_list):
    return [{"label": "TODAS LAS ESPECIES", "value": TODAS_ESPECIES_VALUE}] + [
        {"label": e, "value": e} for e in species_list
    ]

area_options_all = build_area_options(df_base)

# ============================
# 4) Estilos
# ============================
COLORS = {
    "bg": "#f5f7fa",
    "card": "white",
    "accent": "#005f73",
    "muted": "#666666",
    "info_bg": "#eef6f8",
    "info_border": "#005f73",
    "soft_box": "#f9fbfc",
    "soft_border": "#dde7ea",
}

CARD_STYLE = {
    "backgroundColor": COLORS["card"],
    "borderRadius": "8px",
    "padding": "15px",
    "boxShadow": "0 2px 5px rgba(0,0,0,0.08)",
    "marginBottom": "15px",
}

INFO_BOX_STYLE = {
    "marginBottom": "10px",
    "padding": "10px 12px",
    "backgroundColor": COLORS["info_bg"],
    "borderLeft": f"4px solid {COLORS['info_border']}",
    "fontSize": "13px",
    "borderRadius": "4px",
    "lineHeight": "1.5",
}

TOP5_BOX_STYLE = {
    "marginTop": "16px",
    "padding": "12px 14px",
    "backgroundColor": COLORS["soft_box"],
    "border": f"1px solid {COLORS['soft_border']}",
    "borderRadius": "8px",
}

# ============================
# 5) App Layout
# ============================
app = Dash(__name__, requests_pathname_prefix="/apps/amerbs/")

app.layout = html.Div(
    style={"fontFamily": "Arial", "backgroundColor": COLORS["bg"], "minHeight": "100vh"},
    children=[
        html.Div(
            style={"backgroundColor": COLORS["accent"], "color": "white", "padding": "12px 25px"},
            children=[
                html.H1("Desembarques por Área de Manejo (AMERBs)", style={"margin": 0, "fontSize": "22px"}),
                html.Div("Serie de tiempo 1999–2024", style={"fontSize": "13px"}),
            ],
        ),

        html.Div(
            style={"padding": "20px 25px"},
            children=[
                html.Div(
                    style={"display": "flex", "gap": "20px", "flexWrap": "wrap"},
                    children=[
                        # ----- FILTROS -------
                        html.Div(
                            style={"flex": "1 1 260px", "maxWidth": "380px"},
                            children=[
                                html.Div(
                                    style=CARD_STYLE,
                                    children=[
                                        html.H3("Filtros", style={"marginTop": 0}),

                                        html.Label("Regiones"),
                                        dcc.Dropdown(
                                            id="region-dropdown",
                                            options=(
                                                [{"label": "Nacional (todas)", "value": "NACIONAL"}] +
                                                [{"label": map_region_nombre.get(r, r), "value": r} for r in regiones_unicas]
                                            ),
                                            value=[],
                                            multi=True,
                                            placeholder="Selecciona una o más regiones",
                                            style={"marginBottom": "12px"},
                                        ),

                                        html.Label("Áreas de Manejo"),
                                        dcc.Dropdown(
                                            id="area-dropdown",
                                            options=area_options_all,
                                            value=[],
                                            multi=True,
                                            placeholder="Selecciona una o más áreas de manejo",
                                            style={"marginBottom": "12px"},
                                        ),

                                        html.Label("Especies"),
                                        dcc.Dropdown(
                                            id="especie-dropdown",
                                            options=build_species_options(especies_ordenadas),
                                            value=default_especies,
                                            multi=True,
                                            style={"marginBottom": "12px"},
                                        ),
                                    ],
                                )
                            ],
                        ),

                        # ----- GRÁFICO -----
                        html.Div(
                            style={"flex": "3 1 500px"},
                            children=[
                                html.Div(
                                    style=CARD_STYLE,
                                    children=[
                                        html.Div(id="mensaje-contexto", style=INFO_BOX_STYLE),

                                        dcc.Graph(id="grafico-amerbs"),

                                        html.Div(id="top5-especies", style=TOP5_BOX_STYLE),

                                        html.Div(
                                            [
                                                html.Label(
                                                    "Rango de años",
                                                    style={"fontWeight": "bold", "fontSize": "13px", "marginBottom": "4px"},
                                                ),
                                                dcc.RangeSlider(
                                                    id="year-range",
                                                    min=min_year,
                                                    max=max_year,
                                                    value=[min_year, max_year],
                                                    step=1,
                                                    marks={y: str(y) for y in range(min_year, max_year + 1, 5)},
                                                ),
                                            ],
                                            style={"marginTop": "20px"},
                                        ),

                                        html.Div(
                                            [
                                                "Valores: toneladas anuales desembarcadas (con humedad) por especie, agregadas según las Áreas de Manejo seleccionadas."
                                            ],
                                            style={"fontSize": "11px", "color": COLORS["muted"], "marginTop": "10px"},
                                        ),
                                        html.Div(
                                            [
                                                "Elaboración: Instituto Milenio en Socio-Ecología Costera (SECOS) – Datacenter",
                                                html.Br(),
                                                "Fuente: SERNAPESCA (AMERBs 1999–2024)",
                                            ],
                                            style={"fontSize": "11px", "color": COLORS["muted"], "marginTop": "4px"},
                                        ),
                                    ],
                                )
                            ],
                        ),
                    ],
                )
            ],
        ),
    ],
)

# ============================
# 6A) CALLBACK: Filtrar Áreas por Región
# ============================
@app.callback(
    Output("area-dropdown", "options"),
    Output("area-dropdown", "value"),
    Input("region-dropdown", "value"),
    Input("area-dropdown", "value"),
)
def actualizar_areas_por_region(regiones_sel, areas_sel):
    regiones_sel = regiones_sel or []
    areas_sel = areas_sel or []

    if (not regiones_sel) or ("NACIONAL" in regiones_sel):
        return area_options_all, areas_sel

    dff = df_base[df_base["REGION"].isin(regiones_sel)]
    opts = build_area_options(dff)

    valid_values = {o["value"] for o in opts}
    areas_filtradas = [a for a in areas_sel if a in valid_values]

    return opts, areas_filtradas

# ============================
# 6B) CALLBACK: Ajustar especies automáticamente
# - Siempre ofrece "TODAS LAS ESPECIES"
# - Por defecto selecciona las 2 más desembarcadas de la selección actual
# ============================
@app.callback(
    Output("especie-dropdown", "options"),
    Output("especie-dropdown", "value"),
    Input("region-dropdown", "value"),
    Input("area-dropdown", "value"),
)
def actualizar_especies_disponibles(regiones_sel, areas_sel):
    regiones_sel = regiones_sel or []
    areas_sel = areas_sel or []

    dff = df_base.copy()

    regiones_limpias = [r for r in regiones_sel if r != "NACIONAL"]
    if regiones_limpias:
        dff = dff[dff["REGION"].isin(regiones_limpias)]

    if areas_sel:
        if isinstance(areas_sel, str):
            areas_sel = [areas_sel]
        dff = dff[dff["AREA_MANEJO"].isin(areas_sel)]

    especies_locales = (
        dff.groupby("ESPECIE")["TOTAL_TON_HUM"]
        .sum()
        .sort_values(ascending=False)
        .index.tolist()
    )

    if not especies_locales:
        return build_species_options([]), []

    opts = build_species_options(especies_locales)

    defaults = especies_locales[:2]
    if not defaults:
        defaults = especies_locales[:1]

    return opts, defaults

# ============================
# 6C) CALLBACK: Gráfico + Top 5 + mensaje
# ============================
@app.callback(
    Output("grafico-amerbs", "figure"),
    Output("top5-especies", "children"),
    Output("mensaje-contexto", "children"),
    Input("region-dropdown", "value"),
    Input("area-dropdown", "value"),
    Input("especie-dropdown", "value"),
    Input("year-range", "value"),
)
def actualizar_grafico(regiones_sel, areas_sel, especies_sel, year_range):

    dff = df_base.copy()

    regiones_sel = regiones_sel or []
    areas_sel = areas_sel or []

    # Regiones
    regiones_limpias = [r for r in regiones_sel if r != "NACIONAL"]
    if regiones_limpias:
        dff = dff[dff["REGION"].isin(regiones_limpias)]

    # Áreas
    if areas_sel:
        if isinstance(areas_sel, str):
            areas_sel = [areas_sel]
        dff = dff[dff["AREA_MANEJO"].isin(areas_sel)]

    # Años
    a0, a1 = year_range
    dff = dff[(dff["AÑO"] >= a0) & (dff["AÑO"] <= a1)]

    # ============================
    # Mensaje contextual + Top 5
    # ============================
    if areas_sel:
        if not dff.empty:
            resumen_especies = (
                dff.groupby("ESPECIE", as_index=False)["TOTAL_TON_HUM"]
                .sum()
                .sort_values("TOTAL_TON_HUM", ascending=False)
            )

            n_especies = resumen_especies["ESPECIE"].nunique()
            total_periodo = resumen_especies["TOTAL_TON_HUM"].sum()
            top5 = resumen_especies.head(5)
            total_top5 = top5["TOTAL_TON_HUM"].sum()
            pct_top5 = (total_top5 / total_periodo * 100) if total_periodo > 0 else 0

            areas_nodes = build_selected_areas_nodes(areas_sel)

            if len(areas_sel) == 1:
                texto_inicio = " registra desembarques en el periodo seleccionado. "
                texto_segundo = "en esta AMERB."
            else:
                texto_inicio = " registran desembarques en el periodo seleccionado. "
                texto_segundo = "en esta selección de AMERBs."

            mensaje = html.Div([
                html.Div(
                    areas_nodes + [
                        texto_inicio,
                        "El selector de especies ofrece la opción ",
                        html.B("TODAS LAS ESPECIES"),
                        " y, por defecto, muestra las 2 especies más desembarcadas de la selección actual."
                    ]
                ),
                html.Div(
                    [
                        html.B(f"{n_especies} especies "),
                        f"registran desembarque {texto_segundo} ",
                        html.B(f"Top 5 representan {pct_top5:.0f}% "),
                        f"del desembarque para el periodo {a0}–{a1}."
                    ],
                    style={"marginTop": "6px"}
                )
            ])

            top5_children = [
                html.Div(
                    f"Top 5 especies con mayor desembarque acumulado ({a0}–{a1})",
                    style={"fontWeight": "bold", "marginBottom": "8px"}
                ),
                html.Ol(
                    [
                        html.Li(f"{row['ESPECIE']}: {format_tons(row['TOTAL_TON_HUM'])}")
                        for _, row in top5.iterrows()
                    ],
                    style={"margin": 0, "paddingLeft": "20px"}
                )
            ]
        else:
            areas_nodes = build_selected_areas_nodes(areas_sel)

            if len(areas_sel) == 1:
                texto_vacio = f" no registra desembarques para el periodo {a0}–{a1}."
            else:
                texto_vacio = f" no registran desembarques para el periodo {a0}–{a1}."

            mensaje = html.Div([
                html.Div(areas_nodes + [texto_vacio])
            ])

            top5_children = html.Div(
                "No hay desembarques para las áreas seleccionadas en el rango de años elegido."
            )
    else:
        mensaje = html.Div([
            html.Div([
                html.B("Modo general: "),
                "el gráfico muestra, por defecto, las 2 especies más desembarcadas de la selección actual."
            ]),
            html.Div(
                [
                    "También puedes elegir ",
                    html.B("TODAS LAS ESPECIES"),
                    " o seleccionar manualmente una o más especies específicas."
                ],
                style={"marginTop": "6px"}
            )
        ])

        top5_children = html.Div(
            "Selecciona una o más áreas de manejo para ver el resumen automático de especies y el Top 5 de desembarques.",
            style={"color": COLORS["muted"]}
        )

    # ============================
    # Filtrar especies para gráfico
    # ============================
    if isinstance(especies_sel, str):
        especies_sel = [especies_sel]
    especies_sel = especies_sel or []

    if TODAS_ESPECIES_VALUE in especies_sel:
        dff_plot = dff.copy()
    elif especies_sel:
        dff_plot = dff[dff["ESPECIE"].isin(especies_sel)]
    else:
        dff_plot = dff.copy()

    if dff_plot.empty:
        fig = px.line()
        fig.update_layout(
            title="No hay datos disponibles para la selección actual",
            template="simple_white",
            margin={"l": 60, "r": 20, "t": 70, "b": 40},
        )
        fig.update_xaxes(type="linear", dtick=1, tickmode="linear")
        return fig, top5_children, mensaje

    dff_grouped = (
        dff_plot.groupby(["AÑO", "ESPECIE"], as_index=False)["TOTAL_TON_HUM"]
        .sum()
        .sort_values(["ESPECIE", "AÑO"])
    )

    fig = px.line(
        dff_grouped,
        x="AÑO",
        y="TOTAL_TON_HUM",
        color="ESPECIE",
        markers=True,
    )

    # Título dinámico
    if areas_sel:
        titulo = "; ".join([area_label_map.get(a, a) for a in areas_sel])
    else:
        titulo = "Todas las Áreas de Manejo"

    fig.update_layout(
        title=f"Desembarques en Áreas de Manejo (AMERBs)<br><sup>{titulo}</sup>",
        xaxis_title="Año",
        yaxis_title="Toneladas (con humedad)",
        template="simple_white",
        hovermode="x unified",
        margin={"l": 60, "r": 20, "t": 70, "b": 40},
        legend_title_text="Especie",
    )

    fig.update_xaxes(
        type="linear",
        dtick=1,
        tickmode="linear"
    )

    return fig, top5_children, mensaje

# ============================
# 7) RUN
# ============================
if __name__ == "__main__":
    app.run(host="127.0.0.1", port=8056, debug=False)