import pandas as pd
import pyodbc
import argparse
import os
import sys
from datetime import date
from dotenv import load_dotenv

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from helpers.db_resumen import reset_sin_edictos

# Cargar variables de entorno
load_dotenv()

# =============================================================================
# ARGUMENTOS
# =============================================================================
parser = argparse.ArgumentParser(description="Analiza días faltantes por provincia.")
parser.add_argument("--provincia", type=str, required=True, help="Nombre de la provincia")
parser.add_argument("--solo-resumen", action="store_true",
                    help="Solo actualiza la hoja Resumen, no modifica las pestañas individuales")
args = parser.parse_args()

PROVINCIA = args.provincia
SOLO_RESUMEN = args.solo_resumen
FECHA_INICIO = '2016-01-01'
FECHA_FIN = date.today().strftime('%Y-%m-%d')
ARCHIVO_EXCEL = 'analisis_faltantes.xlsx'

# Provincias que no filtran por calendario de boletines (se consideran todos los días hábiles L-V)
PROVINCIAS_SIN_CALENDARIO = []

# Provincias con un único día fijo de publicación semanal (nombre del día en inglés)
# DATEPART(WEEKDAY) con DATEFIRST=7: Lunes=2, Martes=3, Miércoles=4, Jueves=5, Viernes=6
PROVINCIAS_DIA_FIJO = {
    'FORMOSA': {'dia_python': 'Friday', 'dia_sql': 6},
}

CODIGO_AFIP = {
    'SALTA':                          9,
    'BUENOS AIRES':                   1,
    'CIUDAD AUTONOMA DE BUENOS AIRES': 0,
    'SAN LUIS':                       11,
    'ENTRE RIOS':                     5,
    'LA RIOJA':                       8,
    'SANTIAGO DEL ESTERO':            13,
    'CHACO':                          16,
    'SAN JUAN':                       10,
    'CATAMARCA':                      2,
    'LA PAMPA':                       21,
    'MENDOZA':                        7,
    'MISIONES':                       19,
    'FORMOSA':                        18,
    'NEUQUEN':                        20,
    'RIO NEGRO':                      22,
    'SANTA FE':                       12,
    'TUCUMAN':                        14,
    'CHUBUT':                         17,
    'TIERRA DEL FUEGO':               24,
    'CORRIENTES':                     4,
    'CORDOBA':                        3,
    'JUJUY':                          6,
    'SANTA CRUZ':                     23,
    'BORA':                           100,
}

# =============================================================================
# CONFIGURAR CONEXIÓN
# =============================================================================
DB_SERVER = os.getenv('DB_SERVER')
DB_NAME = os.getenv('DB_DATABASE')
DB_USER = os.getenv('DB_USER')
DB_PASSWORD = os.getenv('DB_PASSWORD')
DB_DRIVER = os.getenv('DB_DRIVER', '{ODBC Driver 18 for SQL Server}')

# Validar que las variables de entorno estén configuradas
if not all([DB_SERVER, DB_NAME, DB_USER, DB_PASSWORD]):
    print("ERROR: Faltan variables de entorno para la conexión a la base de datos.")
    print("Asegúrate de tener un archivo .env con:")
    print("  DB_SERVER=tu_servidor")
    print("  DB_DATABASE=tu_base_de_datos")
    print("  DB_USER=tu_usuario")
    print("  DB_PASSWORD=tu_contraseña")
    exit(1)

conn = pyodbc.connect(
    f'DRIVER={DB_DRIVER};'
    f'SERVER={DB_SERVER};'
    f'DATABASE={DB_NAME};'
    f'UID={DB_USER};'
    f'PWD={DB_PASSWORD};'
    f'TrustServerCertificate=yes;'
)

# Query 1
query1 = """
SELECT *
FROM calendario_pers df
LEFT JOIN (
    SELECT DISTINCT fecha_publicacion
    FROM sociedades_constituciones
    WHERE fuente COLLATE Latin1_General_CI_AI = ? COLLATE Latin1_General_CI_AI
) sc ON sc.fecha_publicacion = df.fecha
WHERE df.es_fin_semana = 0
AND df.fecha >= ?
AND df.fecha < ?
AND sc.fecha_publicacion IS NULL
AND NOT EXISTS (
    SELECT 1 FROM feriados_argentina f
    WHERE df.fecha BETWEEN f.fecha AND DATEADD(day, f.duracion - 1, f.fecha)
)
ORDER BY df.fecha;
"""

# Query 2 (con collation insensible a acentos)
query2 = """
SELECT * FROM calendario_boletines_oficiales
WHERE UPPER(provincia_jurisdiccion) COLLATE Latin1_General_CI_AI = UPPER(?) COLLATE Latin1_General_CI_AI
"""

# Query 3 - Total de días esperados (según calendario de publicación)
query3 = """
SELECT COUNT(*) as total
FROM calendario_pers df
INNER JOIN calendario_boletines_oficiales cbo
    ON UPPER(cbo.provincia_jurisdiccion) COLLATE Latin1_General_CI_AI = UPPER(?) COLLATE Latin1_General_CI_AI
WHERE df.es_fin_semana = 0
  AND df.fecha >= ?
  AND df.fecha < ?
  AND (
      (DATEPART(WEEKDAY, df.fecha) = 2 AND cbo.lunes = 1) OR
      (DATEPART(WEEKDAY, df.fecha) = 3 AND cbo.martes = 1) OR
      (DATEPART(WEEKDAY, df.fecha) = 4 AND cbo.miercoles = 1) OR
      (DATEPART(WEEKDAY, df.fecha) = 5 AND cbo.jueves = 1) OR
      (DATEPART(WEEKDAY, df.fecha) = 6 AND cbo.viernes = 1)
  )
  AND NOT EXISTS (
      SELECT 1 FROM feriados_argentina f
      WHERE df.fecha BETWEEN f.fecha AND DATEADD(day, f.duracion - 1, f.fecha)
  )
"""

# Query 3b - Total de días hábiles L-V sin feriados (para provincias sin calendario)
query3b = """
SELECT COUNT(*) as total
FROM calendario_pers df
WHERE df.es_fin_semana = 0
  AND df.fecha >= ?
  AND df.fecha < ?
  AND NOT EXISTS (
      SELECT 1 FROM feriados_argentina f
      WHERE df.fecha BETWEEN f.fecha AND DATEADD(day, f.duracion - 1, f.fecha)
  )
"""

# Query 3c - Total de un día fijo por semana sin feriados (para provincias con publicación semanal fija)
query3c = """
SELECT COUNT(*) as total
FROM calendario_pers df
WHERE df.es_fin_semana = 0
  AND df.fecha >= ?
  AND df.fecha < ?
  AND DATEPART(WEEKDAY, df.fecha) = ?
  AND NOT EXISTS (
      SELECT 1 FROM feriados_argentina f
      WHERE df.fecha BETWEEN f.fecha AND DATEADD(day, f.duracion - 1, f.fecha)
  )
"""

usa_calendario = PROVINCIA.upper() not in PROVINCIAS_SIN_CALENDARIO
dia_fijo = PROVINCIAS_DIA_FIJO.get(PROVINCIA.upper())

print("=" * 70)
print(f"ANÁLISIS DE DÍAS FALTANTES - {PROVINCIA}")
print("=" * 70)
print(f"Servidor: {DB_SERVER}")
print(f"Base de datos: {DB_NAME}")
print(f"Rango: {FECHA_INICIO} a {FECHA_FIN}")
if dia_fijo:
    print(f"Modo: Día fijo semanal ({dia_fijo['dia_python']})")
elif not usa_calendario:
    print(f"Modo: Sin filtro de calendario (todos los días hábiles L-V)")
if SOLO_RESUMEN:
    print("Modo: Solo actualizar Resumen (sin modificar pestañas individuales)")
print("Ejecutando queries...")

# Ejecutar queries
df_faltantes = pd.read_sql(query1, conn, params=[PROVINCIA, FECHA_INICIO, FECHA_FIN])

if dia_fijo:
    df_total_esperado = pd.read_sql(query3c, conn, params=[FECHA_INICIO, FECHA_FIN, dia_fijo['dia_sql']])
elif usa_calendario:
    df_calendario = pd.read_sql(query2, conn, params=[PROVINCIA])
    df_total_esperado = pd.read_sql(query3, conn, params=[PROVINCIA, FECHA_INICIO, FECHA_FIN])

    # Validar que se encontró la provincia
    if df_calendario.empty:
        print(f"ERROR: No se encontró '{PROVINCIA}' en calendario_boletines_oficiales")
        conn.close()
        exit(1)
else:
    df_total_esperado = pd.read_sql(query3b, conn, params=[FECHA_INICIO, FECHA_FIN])

# Crear la columna nombre_dia
df_faltantes['nombre_dia'] = pd.to_datetime(df_faltantes['fecha']).dt.day_name()

if dia_fijo:
    # Filtrar solo el día fijo asignado
    df_resultado = df_faltantes[df_faltantes['nombre_dia'] == dia_fijo['dia_python']]
elif usa_calendario:
    # Obtener días activos del calendario de boletines
    dias_activos = []
    if df_calendario['lunes'].iloc[0] == 1:
        dias_activos.append('Monday')
    if df_calendario['martes'].iloc[0] == 1:
        dias_activos.append('Tuesday')
    if df_calendario['miercoles'].iloc[0] == 1:
        dias_activos.append('Wednesday')
    if df_calendario['jueves'].iloc[0] == 1:
        dias_activos.append('Thursday')
    if df_calendario['viernes'].iloc[0] == 1:
        dias_activos.append('Friday')

    # Filtrar solo días que deberían tener boletín
    df_resultado = df_faltantes[df_faltantes['nombre_dia'].isin(dias_activos)]
else:
    # Sin filtro de calendario: todos los días hábiles (L-V) son esperados
    df_resultado = df_faltantes.copy()

# Calcular estadísticas
total_dias_esperados = df_total_esperado['total'].iloc[0]
dias_faltantes = len(df_resultado)
dias_cargados = total_dias_esperados - dias_faltantes
porcentaje_cargado = (dias_cargados / total_dias_esperados * 100) if total_dias_esperados > 0 else 0
porcentaje_faltante = (dias_faltantes / total_dias_esperados * 100) if total_dias_esperados > 0 else 0

# Mostrar resultados
print(f"\nRESULTADOS:")
print(f"  Días esperados (según calendario): {total_dias_esperados:,}")
print(f"  Días con datos: {dias_cargados:,} ({porcentaje_cargado:.2f}%)")
print(f"  Días faltantes: {dias_faltantes:,} ({porcentaje_faltante:.2f}%)")
print("=" * 70)

# Resetear sin_edictos antes de que los scripts_finales lo acumulen en esta corrida
reset_sin_edictos(PROVINCIA.upper())

# Guardar estadísticas en base de datos
codigo_afip = CODIGO_AFIP.get(PROVINCIA.upper())
if codigo_afip is not None:
    try:
        cursor = conn.cursor()
        cursor.execute(
            "EXEC upsert_estadistica_boletin_resumen ?, ?, ?, ?, ?, ?, ?, ?",
            (
                codigo_afip,
                FECHA_INICIO,
                FECHA_FIN,
                int(total_dias_esperados),
                int(dias_cargados),
                int(dias_faltantes),
                round(porcentaje_cargado, 2),
                round(porcentaje_faltante, 2),
            )
        )
        cursor.execute(
            "EXEC sp_resumen_estado_estadistica ?, ?, ?, ?, ?",
            (
                PROVINCIA.upper(),
                codigo_afip,
                int(dias_faltantes),
                int(dias_cargados),
                int(total_dias_esperados),
            )
        )
        conn.commit()
        cursor.close()
        print(f"✓ Estadísticas guardadas en BD (codigo_afip: {codigo_afip})")
    except Exception as e:
        print(f"⚠ Error al guardar estadísticas en BD: {e}")
else:
    print(f"⚠ No se encontró codigo_afip para '{PROVINCIA}', no se guardó en BD")

# =============================================================================
# GENERAR EXCEL (ACUMULATIVO)
# =============================================================================
archivo_existe = os.path.exists(ARCHIVO_EXCEL)

if archivo_existe:
    print(f"\nArchivo existente detectado. Actualizando provincia: {PROVINCIA}...")
    try:
        df_resumen_existente = pd.read_excel(ARCHIVO_EXCEL, sheet_name='Resumen')
    except Exception as e:
        print(f"  ⚠ Archivo corrupto o inválido ({e}). Se creará uno nuevo.")
        archivo_existe = False
        df_resumen_existente = pd.DataFrame(columns=['Provincia', 'Fecha Inicio', 'Fecha Fin',
                                                       'Días Esperados', 'Días con Datos', 'Días Faltantes',
                                                       'Porcentaje Cargado', 'Porcentaje Faltante'])
else:
    print(f"\nCreando nuevo archivo Excel: {ARCHIVO_EXCEL}...")
    df_resumen_existente = pd.DataFrame(columns=['Provincia', 'Fecha Inicio', 'Fecha Fin',
                                                   'Días Esperados', 'Días con Datos', 'Días Faltantes',
                                                   'Porcentaje Cargado', 'Porcentaje Faltante'])

# Preparar datos de faltantes para Excel
if len(df_resultado) > 0:
    df_resultado['fecha_formato'] = pd.to_datetime(df_resultado['fecha']).dt.strftime('%d/%m/%Y')
    df_resultado['mes'] = pd.to_datetime(df_resultado['fecha']).dt.month_name()
    df_resultado['año'] = pd.to_datetime(df_resultado['fecha']).dt.strftime('%Y')  # Como texto para evitar formato con comas

    df_export = df_resultado[['fecha_formato', 'nombre_dia', 'mes', 'año']].copy()
    df_export.columns = ['Fecha', 'Día de la semana', 'Mes', 'Año']

# Crear fila de resumen para la provincia actual
nueva_fila = pd.DataFrame([{
    'Provincia': PROVINCIA,
    'Fecha Inicio': FECHA_INICIO,
    'Fecha Fin': FECHA_FIN,
    'Días Esperados': total_dias_esperados,
    'Días con Datos': dias_cargados,
    'Días Faltantes': dias_faltantes,
    'Porcentaje Cargado': f"{porcentaje_cargado:.2f}%",
    'Porcentaje Faltante': f"{porcentaje_faltante:.2f}%"
}])

# Si la provincia ya existe, actualizarla; si no, agregarla
if PROVINCIA in df_resumen_existente['Provincia'].values:
    df_resumen_existente = df_resumen_existente[df_resumen_existente['Provincia'] != PROVINCIA]
    print(f"  ⚠ Provincia {PROVINCIA} ya existía. Actualizando datos...")

df_resumen_final = pd.concat([df_resumen_existente, nueva_fila], ignore_index=True)

# Ordenar por provincia
df_resumen_final = df_resumen_final.sort_values('Provincia').reset_index(drop=True)

# Escribir Excel
if archivo_existe:
    with pd.ExcelWriter(ARCHIVO_EXCEL, engine='openpyxl', mode='a', if_sheet_exists='replace') as writer:
        # Actualizar hoja de resumen
        df_resumen_final.to_excel(writer, sheet_name='Resumen', index=False)

        # Solo actualizar hoja de provincia si NO es modo solo-resumen
        if not SOLO_RESUMEN:
            # Agregar o actualizar hoja de la provincia
            sheet_name_provincia = PROVINCIA[:31]
            if len(df_resultado) > 0:
                df_export.to_excel(writer, sheet_name=sheet_name_provincia, index=False)
            else:
                df_vacio = pd.DataFrame({'Mensaje': ['No hay días faltantes']})
                df_vacio.to_excel(writer, sheet_name=sheet_name_provincia, index=False)

        # Ajustar ancho de columnas
        for sheet_name in writer.sheets:
            worksheet = writer.sheets[sheet_name]
            for column in worksheet.columns:
                max_length = 0
                column_letter = column[0].column_letter
                for cell in column:
                    try:
                        if len(str(cell.value)) > max_length:
                            max_length = len(str(cell.value))
                    except:
                        pass
                adjusted_width = min(max_length + 2, 50)
                worksheet.column_dimensions[column_letter].width = adjusted_width
else:
    # Crear nuevo archivo
    with pd.ExcelWriter(ARCHIVO_EXCEL, engine='openpyxl') as writer:
        # Escribir resumen
        df_resumen_final.to_excel(writer, sheet_name='Resumen', index=False)

        # Escribir hoja de la provincia
        sheet_name_provincia = PROVINCIA[:31]
        if len(df_resultado) > 0:
            df_export.to_excel(writer, sheet_name=sheet_name_provincia, index=False)
        else:
            df_vacio = pd.DataFrame({'Mensaje': ['No hay días faltantes']})
            df_vacio.to_excel(writer, sheet_name=sheet_name_provincia, index=False)

        # Ajustar ancho de columnas
        for sheet_name in writer.sheets:
            worksheet = writer.sheets[sheet_name]
            for column in worksheet.columns:
                max_length = 0
                column_letter = column[0].column_letter
                for cell in column:
                    try:
                        if len(str(cell.value)) > max_length:
                            max_length = len(str(cell.value))
                    except:
                        pass
                adjusted_width = min(max_length + 2, 50)
                worksheet.column_dimensions[column_letter].width = adjusted_width

if SOLO_RESUMEN:
    print(f"✓ Excel actualizado (solo hoja Resumen): {ARCHIVO_EXCEL}")
else:
    print(f"✓ Excel actualizado (Resumen + hoja {PROVINCIA}): {ARCHIVO_EXCEL}")

if len(df_resultado) > 0:
    print(f"\n📅 PRIMEROS 10 DÍAS FALTANTES:")
    for i, row in df_resultado.head(10).iterrows():
        print(f"  {i+1}. {row['fecha_formato']} - {row['nombre_dia']}")

    if len(df_resultado) > 10:
        print(f"  ... y {len(df_resultado) - 10} días más")

print(f"\n✓ Análisis completado.\n")

# Cerrar conexión
conn.close()