# -*- coding: utf-8 -*-
from flask import Flask, request, jsonify
import urllib.request
import urllib.error
import urllib.parse
import gzip
import zlib
import json
from io import BytesIO

app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False # Permite exportar la 'Ñ' y tildes visualmente en el JSON final

# =======================================================
# HERRAMIENTAS INTERNAS
# =======================================================
def read_response(response):
    """Lee y decodifica inteligentemente para no perder la Ñ y tildes"""
    # 1. Extraer los bytes crudos dependiendo de la compresión
    if response.info().get('Content-Encoding') == 'gzip':
        buf = BytesIO(response.read())
        raw_bytes = gzip.GzipFile(fileobj=buf).read()
    elif response.info().get('Content-Encoding') == 'deflate':
        decompress = zlib.decompressobj(-zlib.MAX_WBITS)
        raw_bytes = decompress.decompress(response.read())
        raw_bytes += decompress.flush()
    else:
        raw_bytes = response.read()
        
    # 2. Decodificación con rescate de formato (Evita que se borre la Ñ)
    try:
        return raw_bytes.decode('utf-8')
    except UnicodeDecodeError:
        return raw_bytes.decode('iso-8859-1', errors='replace')

def extraer_ubicacion_html(html_str):
    """Extrae el texto visible de un <option selected value='...'>TEXTO</option>"""
    texto = str(html_str)
    if "selected value=" not in texto:
        return ""
    try:
        start_val = texto.find("selected value=")
        start_tag_end = texto.find(">", start_val) + 1
        end_tag = texto.find("<", start_tag_end)
        if start_tag_end > 0 and end_tag > 0:
            return texto[start_tag_end:end_tag].strip()
    except:
        pass
    return ""

def obtener_dpto(codigo):
    ubigeo = {
        "01": "AMAZONAS", "02": "ANCASH", "03": "APURIMAC", "04": "AREQUIPA", 
        "05": "AYACUCHO", "06": "CAJAMARCA", "07": "CALLAO", "08": "CUSCO", 
        "09": "HUANCAVELICA", "10": "HUANUCO", "11": "ICA", "12": "JUNIN", 
        "13": "LA LIBERTAD", "14": "LAMBAYEQUE", "15": "LIMA", "16": "LORETO", 
        "17": "MADRE DE DIOS", "18": "MOQUEGUA", "19": "PASCO", "20": "PIURA", 
        "21": "PUNO", "22": "SAN MARTIN", "23": "TACNA", "24": "TUMBES", "25": "UCAYALI"
    }
    return ubigeo.get(str(codigo).strip().zfill(2), str(codigo))

def parsear_datos_subsidiado(lista, dni):
    """Procesa el array gigante del SIS Subsidiado aplicando la lógica exacta (C# adaptado)"""
    res = {}
    
    # 1. TIPO DE SEGURO Y CORRECCIÓN DE TEXTO (Ñ)
    tipo_bruto = f"{str(lista[81]).strip()} - {str(lista[77]).strip()}"
    tipo_bruto = tipo_bruto.replace("NIOS", "NIÑOS").replace("AOS", "AÑOS")
    res["tipo_seguro"] = tipo_bruto
    
    res["plan_beneficios"] = str(lista[82]).strip()
    res["fecha_afiliacion"] = f"{lista[4]}/{lista[5]}/{lista[6]}"
    res["contrato"] = f"{lista[1]} - {lista[2]} - {lista[3]}"
    res["eess"] = str(lista[30]).strip()
    
    # 2. ESTADO Y MOTIVO DE ANULACIÓN
    estado_val = str(lista[56]).strip()
    res["estado"] = "ACTIVO" if estado_val == "0" else "CANCELADO"
    res["motivo_anulacion"] = ""
    
    if len(lista) > 64 and str(lista[60]).strip() != "":
        motivo = f"ANULADO por {lista[60]} {lista[61]}/{lista[62]}/{lista[63]} | {lista[64]}"
        res["motivo_anulacion"] = motivo
        res["estado"] = f"CANCELADO ({motivo})"

    # 3. UBICACIÓN GEOGRÁFICA DEL EESS
    dpto = obtener_dpto(lista[19])
    prov = extraer_ubicacion_html(lista[20])
    dist = extraer_ubicacion_html(lista[22])
    ccpp = extraer_ubicacion_html(lista[24]) if len(lista) > 24 else ""
    
    ubicacion_parts = [p for p in [dpto, prov, dist, ccpp] if p]
    res["ubicacion_eess"] = " / ".join(ubicacion_parts)
    
    return res

# =======================================================
# LLAMADAS A SERVICIOS EXTERNOS (Webscraping / APIs)
# =======================================================
def llamar_webservis_sis(d, t, n, c, cod):
    req = urllib.request.Request("http://app.sis.gob.pe/EDI/RecepcionTrama.asmx", method="POST")
    req.add_header("SOAPAction", '"http://www.sis.gob.pe/BuscarAsegurados"')
    req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/101.0.4951.54")
    req.add_header("Content-Type", "text/xml; charset=UTF-8")
    req.add_header("Accept-Encoding", "gzip, deflate")
    req.add_header("Cookie", "_ga=GA1.1.280939332.1627866997; ASP.NET_SessionId=mksnln1gad3ydciwckeipnqh; pCookie=cok_NombreUsuario=AZABACHE FLORES, EDWIN ELOY&cok_Dni=43084477&cok_DISA=140&cok_GMR=1&cok_ODSIS=015&cok_ODSIS_NOMBRE=HUANUCO&cok_EMAIL=eloyazabache45@hotmail.com&cok_CEN_LUG_CODIGO=5&cok_CEN_DIG_CODIGO=1&cok_CEN_DIG_NOMBRE=ESTABLECIMIENTO DE SALUD&cok_USU_ID=8778&cok_idRed=0&cok_CT_NOMBRE=EESS - EESS&cok_CP=&cok_CP_NOMBRE=&cok_UndEje=1110&cok_EESS=100601A302&cok_usuario=FAZABACHE&cok_ppdd=029&cok_SID=mksnln1gad3ydciwckeipnqh&FAR=N&cok_UndEje_NOMBRE=REGION HUANUCO - SALUD LEONCIO PRADO&cok_departamento=10&cok_departamento_NOMBRE=HUANUCO&cok_flag_nuevo_convenio=N&cok_disa_nombre=DISA HUANUCO&cok_es_diresa=N; intra=codusu=FAZABACHE&nombre=AZABACHE FLORES, EDWIN ELOY&odsis=015&disabv=LM1&disa=140; _ga_46MDWJTQHC=GS1.1.1651891465.25.1.1651891482.0; sis=tipocarga=2")
    
    body = f'''<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body><BuscarAsegurados xmlns="http://www.sis.gob.pe/"><Disa>{d}</Disa><TipoFormato>{t}</TipoFormato><Contrato>{n}</Contrato><Correlativo>{c}</Correlativo><CodTabla>{cod}</CodTabla></BuscarAsegurados></Body></Envelope>'''
    try:
        resp = urllib.request.urlopen(req, data=body.encode('utf-8'), timeout=10)
        txt = read_response(resp)
        if len(txt) > 405:
            start = txt.find("Result") + 7
            end = txt.find("Buscar", start) - 2
            return txt[start:end].strip().split("|")
    except: pass
    return []

def llamar_webserv_subsidiado(tdoc, doc):
    req = urllib.request.Request("http://app.sis.gob.pe/sisERP/sisAfiliacionAUS03/ajax/appSegurosInt.frmAfiliacionAUS,appSegurosInt.ashx?_method=Buscar&_session=no", method="POST")
    req.add_header("Content-Type", "text/plain;charset=UTF-8")
    req.add_header("User-Agent", "Mozilla/5.0 Chrome/84.0.4147.105")
    body = f"Disa=140\nTipoFormato={tdoc}\nNumRegManual={doc}"
    try:
        resp = urllib.request.urlopen(req, data=body.encode('utf-8'), timeout=10)
        txt = read_response(resp)
        txt_limpio = txt.replace('["', '').replace('"]', '').replace('"', '').strip()
        if len(txt_limpio) > 5:
            return txt_limpio.split("$")
    except: pass
    return []

# =======================================================
# LOGICAS DE EXTRACCION SEPARADAS (Modulos)
# =======================================================
def fetch_minsa(dni):
    try:
        req = urllib.request.Request("https://websalud.minsa.gob.pe/hisminsa/his/personal")
        req.add_header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
        req.add_header("X-Requested-With", "XMLHttpRequest")
        req.add_header("User-Agent", "Mozilla/5.0 Chrome/102.0.0.0")
        req.add_header("Origin", "https://websalud.minsa.gob.pe")
        req.add_header("Referer", "https://websalud.minsa.gob.pe/hisminsa/")
        req.add_header("Cookie", "JSESSIONID=636F0733ADDFC51373368B41F34C124B; rxVisitor=1655173420842I562BSFCTLJQFVCBAN13L96TPI652H06; cf_chl_2=7b1449bb7a0c74a; cf_chl_prog=x12; cf_clearance=uXjy0pZea1Hu7v3fv0EY0t48zh5sIUqdp5Wn9J_KGZk-1655392250-0-150; dtSa=-; dtPC=1$592968704_644h-vHBDINTKFGEMOCPIGFETIOMFMKDJCBGKU; dtLatC=1; byt=6d3a24476349aa99628f3e9983041106748cb43f5bde60bf959e66add24c41f86572f4421d25b5751441b0de6b843f072c68de06ed08585658b1cfdaafbb7932b32f400926a5ca27dd4a9971afe20732ee64a715bdf243af3be5b6ade99dea75; rxvt=1655394805187|1655391203139; dtCookie=1$676EFBC767EE7FF307BADD6EA684439E|HISMINSA|1|RUM+Default+Application|1")
        
        body = f"C=PERSONAL&S=INFOGETBYID&idtipodocper=1&numdocper={dni}".encode('utf-8')
        resp = urllib.request.urlopen(req, data=body, timeout=10)
        datos = json.loads(read_response(resp))
        
        if not datos or "nombper" not in datos or not str(datos.get("nombper")).strip():
            return {"error": "VERIFICA QUE EL NUMERO DE DOCUMENTO ESTA CORRECTO"}
        return datos
    except Exception:
        return {"error": "VERIFICA QUE EL NUMERO DE DOCUMENTO ESTA CORRECTO"}

def fetch_sis(dni):
    resultado = {"estado": "NO CUENTA CON SIS", "tipo_seguro": "", "plan_beneficios": "", "contrato": "", "fecha_afiliacion": "", "eess": "", "ubicacion_eess": "", "motivo_anulacion": ""}
    try:
        req_cod = urllib.request.Request("http://app.sis.gob.pe/sisERP/sisNRUS/01AfiliacionNRUS/frmActualizacionNRUS.aspx/TieneAfiliacion", method="POST")
        req_cod.add_header("Accept", "application/json")
        req_cod.add_header("Content-Type", "application/json; charset=UTF-8")
        req_cod.add_header("Cookie", "ASP.NET_SessionId=rnpcz13rsduidf1dt21xgxcj; pCookie=cok_NombreUsuario=AZABACHE FLORES, EDWIN ELOY&cok_Dni=43084477&cok_DISA=140; sis=tipocarga=1")
        
        resp_cod = urllib.request.urlopen(req_cod, data=json.dumps({"TipoDocumento": "1", "DNI": dni}).encode('utf-8'), timeout=10)
        api_obtenercod = read_response(resp_cod)
        
        if len(api_obtenercod) >= 27:
            disax, tipox, numerox, codtablax = api_obtenercod[9:12], api_obtenercod[13:14], api_obtenercod[15:23], api_obtenercod[24:25]
            
            if tipox == "2":
                lista = llamar_webserv_subsidiado("2", dni)
                if lista and len(lista) >= 82:
                    resultado.update(parsear_datos_subsidiado(lista, dni))
                else:
                    # Mantenimiento / SOAP (Fallback)
                    lista_semi = llamar_webservis_sis(disax, tipox, numerox, "", codtablax)
                    if len(lista_semi) >= 20:
                        resultado.update({
                            "estado": "ACTIVO", "fecha_afiliacion": lista_semi[8], "contrato": f"{lista_semi[2]}-{lista_semi[3]}-{lista_semi[4]}",
                            "tipo_seguro": "SUBSIDIADO (SIS GRATUITO)", "eess": lista_semi[7],
                            "plan_beneficios": "PEAS MAS PLANES COMPLEMENTARIOS"
                        })
            
            elif tipox in ["9", "R", "8"]:
                cod = "00" if tipox in ["9", "R"] else ""
                lista_semi = llamar_webservis_sis(disax, tipox, numerox, cod, codtablax)
                if len(lista_semi) >= 20:
                    if tipox == "9": tipo_s = "SIS INDEPENDIENTE"
                    elif tipox == "R": tipo_s = "SIS NRUS (SIS EMPRENDEDOR)"
                    else: tipo_s = "SIS MICROEMPRESAS"
                    
                    resultado.update({
                        "estado": f"ACTIVO hasta {lista_semi[17]}", "fecha_afiliacion": lista_semi[8], "contrato": f"{lista_semi[2]}-{lista_semi[3]}-{lista_semi[4]}",
                        "tipo_seguro": tipo_s, "eess": lista_semi[7],
                        "plan_beneficios": "PEAS MAS PLANES COMPLEMENTARIOS"
                    })
        else:
            # Rescate Final SIS Subsidiado
            lista = llamar_webserv_subsidiado("2", dni)
            if lista and len(lista) >= 82:
                resultado.update(parsear_datos_subsidiado(lista, dni))

    except Exception as e:
        print("Error SIS:", e)
    return resultado

def fetch_essalud(dni, fecha_nac):
    resultado_vacio = {"estado": "NO TIENE SEGURO", "tipo_seguro": "NO TIENE SEGURO", "plan_beneficios": "", "contrato": "", "fecha_afiliacion": "", "eess": "", "ubicacion_eess": "", "motivo_anulacion": ""}
    try:
        multiplicadores = [3, 2, 7, 6, 5, 4, 3, 2]
        suma = sum(int(dni[i]) * multiplicadores[i] for i in range(8))
        op = 11 - (suma % 11)
        if op == 11: op = 0
        digitos_map = ["6", "7", "8", "9", "0", "1", "1", "2", "3", "4", "5"]
        digito_verificador = digitos_map[op]

        req = urllib.request.Request("https://apps.essalud.gob.pe/dondemeatiendo-service/api/consultarAcreditacion?captchaToken=-", method="POST")
        req.add_header("Content-Type", "application/json")
        req.add_header("User-Agent", "Mozilla/5.0 Chrome/126.0.0.0")
        
        body = json.dumps({"codOpcion": "1", "codTipDoc": "1", "numDoc": dni, "digitoVerif": digito_verificador, "fecNacimiento": fecha_nac})
        resp = urllib.request.urlopen(req, data=body.encode('utf-8'), timeout=10)
        txt = read_response(resp)

        if "incorrectos" in txt.lower() or "no encontrado" in txt.lower():
            return resultado_vacio

        data = json.loads(txt)
        if isinstance(data, list) and len(data) > 0: data = data[0]
        
        if "vDataItem" in data:
            item = data["vDataItem"]
            if isinstance(item, list) and len(item) > 0: item = item[0]

            tipo_seg = item.get("tipoSeguro")
            vigencia_ini = item.get("inicioVigenciaAcreditacion")

            if not tipo_seg or not vigencia_ini:
                return resultado_vacio

            return {
                "estado": "AFILIADO ACTIVO",
                "tipo_seguro": f"ESSALUD - {tipo_seg}",
                "contrato": item.get("autogeneradoTitular", ""),
                "plan_beneficios": item.get("tipoAsegurado", ""),
                "fecha_afiliacion": f"Inicio: {vigencia_ini} - Fin: {item.get('finVigenciaAcreditacion', '')}",
                "eess": f"{item.get('codCentro', '')} : {item.get('desCentro', '')} - {item.get('red', '')}",
                "ubicacion_eess": "",
                "motivo_anulacion": ""
            }
        return resultado_vacio
    except:
        return resultado_vacio

# =======================================================
# ENDPOINT MAESTRO: CONSULTAR ORQUESTADO
# =======================================================
@app.route('/consultar', methods=['GET'])
def consultar_integral():
    dni = request.args.get('dni')
    if not dni or len(dni) != 8:
        return jsonify({"error": "DNI invalido"}), 400

    # PASO 1: VALIDAR MINSA / RENIEC
    datos_paciente = fetch_minsa(dni)
    if "error" in datos_paciente:
        return jsonify(datos_paciente), 200

    fecha_nac = datos_paciente.get("fechnacper", "")

    # PASO 2: BUSCAR EN SIS
    datos_seguro = fetch_sis(dni)
    estado_sis = datos_seguro.get("estado", "")

    # PASO 3: SI NO TIENE SIS *O ESTÁ CANCELADO*, BUSCAR EN ESSALUD
    # Si encuentra en EsSalud, lo pisa. Si EsSalud no encuentra nada, MANTIENE el historial de "CANCELADO" del SIS.
    if "NO CUENTA CON SIS" in estado_sis or "CANCELADO" in estado_sis or not datos_seguro.get("tipo_seguro"):
        if fecha_nac:
            datos_essalud = fetch_essalud(dni, fecha_nac)
            
            # Si EsSalud lo tiene ACTIVO, usamos EsSalud
            if datos_essalud.get("estado") == "AFILIADO ACTIVO":
                datos_seguro = datos_essalud
            # Si EsSalud NO tiene nada, pero en SIS tampoco tenía nada (no estaba cancelado), mandamos vacío
            elif "CANCELADO" not in estado_sis:
                datos_seguro = datos_essalud
            # Si estaba CANCELADO en SIS, ignoramos el "NO TIENE SEGURO" de EsSalud y conservamos la info del SIS.
        else:
            # Si no hay fecha_nac y tampoco era un seguro CANCELADO en SIS
            if "CANCELADO" not in estado_sis:
                datos_seguro = {"tipo_seguro": "NO TIENE SEGURO", "estado": "NO TIENE SEGURO", "plan_beneficios": "", "contrato": "", "fecha_afiliacion": "", "eess": "", "ubicacion_eess": "", "motivo_anulacion": ""}

    # UNIFICAR Y ENVIAR AL FRONTEND
    datos_paciente.update(datos_seguro)
    
    return jsonify(datos_paciente)

if __name__ == '__main__':
    # host='0.0.0.0' permite que Docker exponga el puerto internamente
    app.run(host='0.0.0.0', port=5000)