import pandas as pd
import unicodedata
from pathlib import Path


NOTA_TECNICA_FILE = Path(__file__).with_name("NOTA TECNICA PPL AJUSTADA. (1) 1.xlsx")
TABLA_REFERENCIA_FILE = Path(__file__).with_name("TablaReferencia_CUPS__1-2024 (1).xlsx")

NOTA_TECNICA_SHEET = "NOTA TECNICA GENERAL"
TABLA_REFERENCIA_SHEET = "Table"

OUTPUT_REFERENCIA_SQL = Path(__file__).with_name("cups_referencia.sql")
OUTPUT_CUBIERTOS_SQL = Path(__file__).with_name("cups_cubiertos.sql")


def _to_text(value):
    if pd.isna(value):
        return ""
    return str(value).strip()


def _sql_text(value):
    if value is None:
        return "NULL"
    text = str(value).strip()
    if text == "":
        return "NULL"
    text = text.replace("'", "''")
    return f"'{text}'"


def _normalize_text(value):
    raw = _to_text(value)
    if raw == "":
        return ""
    normalized = unicodedata.normalize("NFD", raw)
    without_marks = "".join(ch for ch in normalized if unicodedata.category(ch) != "Mn")
    return without_marks.upper()


def _find_header_row(df, marker="CUPS"):
    upper_marker = marker.strip().upper()
    for idx, row in df.iterrows():
        if row.astype(str).str.strip().str.upper().eq(upper_marker).any():
            return idx
    return None


def _pick_column(columns, candidates):
    upper = {str(col).strip().upper(): col for col in columns}
    for candidate in candidates:
        key = candidate.strip().upper()
        if key in upper:
            return upper[key]
    return None


def _resolve_sheet(file_path, desired_name):
    xls = pd.ExcelFile(file_path)
    for name in xls.sheet_names:
        if name.strip().lower() == desired_name.strip().lower():
            return name
    return desired_name


def cargar_cups_cubiertos():
    sheet_name = _resolve_sheet(NOTA_TECNICA_FILE, NOTA_TECNICA_SHEET)
    df = pd.read_excel(NOTA_TECNICA_FILE, sheet_name=sheet_name, dtype=str)
    header_idx = _find_header_row(df, "CUPS")
    if header_idx is None:
        raise ValueError("No se encontro la fila de encabezados con CUPS.")

    headers = df.iloc[header_idx].astype(str).str.strip()
    data = df.iloc[header_idx + 1 :].copy()
    data.columns = headers

    col_codigo = _pick_column(data.columns, ["CUPS", "CODIGO", "CODIGO CUPS"])
    col_descripcion = _pick_column(data.columns, ["DESCRIPCION", "DESCRIPCION CUPS", "NOMBRE"])
    col_especialidad = _pick_column(data.columns, ["ESPECIALIDAD"])

    if not col_codigo or not col_descripcion:
        raise ValueError("No se encontraron columnas de CUPS o descripcion en la nota tecnica.")

    select_cols = [col_codigo, col_descripcion]
    if col_especialidad:
        select_cols.append(col_especialidad)

    data = data[select_cols].rename(
        columns={
            col_codigo: "codigo",
            col_descripcion: "descripcion",
            col_especialidad: "especialidad_raw",
        }
    )

    data["codigo"] = data["codigo"].map(_to_text)
    data["descripcion"] = data["descripcion"].map(_to_text)
    data["descripcion_busqueda"] = data["descripcion"].map(_normalize_text)
    if "especialidad_raw" in data.columns:
        data["especialidad_raw"] = data["especialidad_raw"].map(_to_text)
    else:
        data["especialidad_raw"] = ""

    def _parse_nivel(value):
        raw = _to_text(value).upper()
        if raw.startswith("NIVEL"):
            return raw
        return ""

    data["nivel"] = data["especialidad_raw"].map(_parse_nivel)
    data["especialidad"] = data["especialidad_raw"].apply(
        lambda v: "" if _parse_nivel(v) else _to_text(v)
    )
    data = data[data["codigo"] != ""]
    data = data.drop_duplicates(subset=["codigo"])

    return data


def cargar_cups_referencia():
    sheet_name = _resolve_sheet(TABLA_REFERENCIA_FILE, TABLA_REFERENCIA_SHEET)
    df = pd.read_excel(TABLA_REFERENCIA_FILE, sheet_name=sheet_name, dtype=str)
    col_codigo = _pick_column(df.columns, ["Codigo", "Código", "CODIGO"])
    col_descripcion = _pick_column(df.columns, ["Nombre", "Descripcion", "Descripción"])

    if not col_codigo or not col_descripcion:
        raise ValueError("No se encontraron columnas de Codigo o Descripcion en la tabla de referencia.")

    data = df[[col_codigo, col_descripcion]].rename(
        columns={col_codigo: "codigo", col_descripcion: "descripcion"}
    )

    data["codigo"] = data["codigo"].map(_to_text)
    data["descripcion"] = data["descripcion"].map(_to_text)
    data = data[data["codigo"] != ""]
    data = data.drop_duplicates(subset=["codigo"])

    return data


def generar_sql_referencia(dataframe):
    lines = ["-- UPSERTS TABLA cups_referencia"]
    for _, row in dataframe.iterrows():
        codigo = _sql_text(row["codigo"])
        descripcion = _sql_text(row["descripcion"])
        if codigo == "NULL" or descripcion == "NULL":
            continue
        lines.append(
            "INSERT INTO cups_referencia (codigo, descripcion) "
            f"VALUES ({codigo}, {descripcion}) "
            "ON CONFLICT (codigo) DO UPDATE SET descripcion = EXCLUDED.descripcion;"
        )
    OUTPUT_REFERENCIA_SQL.write_text("\n".join(lines) + "\n", encoding="utf-8")


def generar_sql_cubiertos(dataframe):
    lines = [
        "-- UPSERTS TABLA cups_cubiertos",
        "UPDATE cups_cubiertos SET activo = false;",
    ]
    for _, row in dataframe.iterrows():
        codigo = _sql_text(row["codigo"])
        descripcion = _sql_text(row["descripcion"])
        descripcion_busqueda = _sql_text(row["descripcion_busqueda"])
        nivel = _sql_text(row.get("nivel", ""))
        especialidad = _sql_text(row.get("especialidad", ""))
        if codigo == "NULL" or descripcion == "NULL":
            continue
        lines.append(
            "INSERT INTO cups_cubiertos "
            "(codigo, descripcion, descripcion_busqueda, nivel, especialidad, activo) "
            f"VALUES ({codigo}, {descripcion}, {descripcion_busqueda}, {nivel}, {especialidad}, true) "
            "ON CONFLICT (codigo) DO UPDATE SET "
            "descripcion = EXCLUDED.descripcion, "
            "descripcion_busqueda = EXCLUDED.descripcion_busqueda, "
            "nivel = EXCLUDED.nivel, "
            "especialidad = EXCLUDED.especialidad, "
            "activo = true;"
        )
    OUTPUT_CUBIERTOS_SQL.write_text("\n".join(lines) + "\n", encoding="utf-8")


def main():
    if not NOTA_TECNICA_FILE.exists():
        raise FileNotFoundError(f"No se encuentra el archivo: {NOTA_TECNICA_FILE}")
    if not TABLA_REFERENCIA_FILE.exists():
        raise FileNotFoundError(f"No se encuentra el archivo: {TABLA_REFERENCIA_FILE}")

    cubiertos = cargar_cups_cubiertos()
    referencia = cargar_cups_referencia()

    generar_sql_referencia(referencia)
    generar_sql_cubiertos(cubiertos)

    print("Archivos generados:")
    print(f"  {OUTPUT_REFERENCIA_SQL} ({len(referencia)} registros)")
    print(f"  {OUTPUT_CUBIERTOS_SQL} ({len(cubiertos)} registros)")


if __name__ == "__main__":
    main()
