import asyncio
import random
import secrets
import threading
import time
import curl_cffi
from aiolimiter import AsyncLimiter
from curl_cffi.requests import AsyncSession
from selectolax.parser import HTMLParser
from colorama import init, Fore, Style

def obtener_diferencia(list1, list2):
    return list(set(list1) ^ set(list2))


init()
class Generator:
    def __init__(self):
        self.stats = {'b': 0, 'm': 0, 'c': 0, 'r': 0}
        self.sem = AsyncLimiter(90, 2)
        self.proxy_good = set()
        self.num = list()
        self.sublist = None
        self.proxylist = list()
    @staticmethod
    def read_file(file_path):
        """Read lines from a file and return as a list."""
        with open(file_path, "r") as file:
            return [line.strip() for line in file]

    @staticmethod
    def write_file(file_path, data):
        """Read lines from a file and return as a list."""
        with open(file_path, "a") as file:
            for item in data:
                file.write(f"{item}\n")

    @staticmethod
    def format_proxy(proxy):
        """Format a proxy string."""
        # Implementar la función de formateo de proxy aquí
        partes_proxy = proxy.split(':')
        ip_port = partes_proxy[0]
        port = partes_proxy[1]
        username = partes_proxy[2]
        password = partes_proxy[3]
        proxy_formateado = f"{username}:{password}@{ip_port}:{port}"
        return proxy_formateado

    @staticmethod
    def get_info(info):
        parse_html = HTMLParser(info)

        # Buscar el elemento #ValorTotalEdit
        saldo_elements = parse_html.css('#ValorTotalEdit')
        if saldo_elements:
            for elem in saldo_elements:
                saldo_text = elem.child.html.strip().replace('$', '').replace('.', '').replace(' ', '').split(',')[0]
                if not saldo_text:
                    print("OJOSALDO")
                try:
                    saldo = int(saldo_text)
                    if saldo > 0:
                        return f'${saldo}'
                    else:
                        return "Saldo en 0"
                except ValueError:
                    return "Saldo no válido"

        # Buscar el elemento #msg_error
        error_elements = parse_html.css('#msg_error')
        if error_elements:
            for elem in error_elements:
                error_text = elem.child.html.strip()
                if not error_text:
                    return "Error"
                if "Estas al día en tus pagos. Próxima carga Voz y/o Datos" in error_text:
                    return error_text.replace('Estas al día en tus pagos. Próxima carga Voz y/o Datos ', '')
                else:
                    return error_text

        # Si no se encuentra ningún elemento esperado
        return "Error"

    async def get_cookie(self, selected_proxy):
        """Placeholder for the get_cookie function."""
        # Implementar la lógica de get_cookie aquí
        async with AsyncLimiter(80, 2):
            proxy = {
                "http": f"http://{selected_proxy}",
                "https": f"http://{selected_proxy}"
            }
            url = 'https://portalpagos.claro.com.co/phrame.php?action=despliegue_personal&clase=VistasClaroComprobante&metodo=generarComprobante&empresa=claro'
            while True:
                try:
                    async with AsyncSession(impersonate="chrome99_android", proxies=proxy) as s:
                        r = await s.get(url)
                    self.proxy_good.add(selected_proxy)
                    break
                except curl_cffi.requests.errors.RequestsError as e:
                    if "curl: (28)" in str(e):
                        selected_proxy = random.choice(list(self.proxy_good))
                        proxy = {
                            "http": f"http://{selected_proxy}",
                            "https": f"http://{selected_proxy}"
                        }
            return r.cookies

    async def search_data(self, num, cookie, selected_proxy):
        async with self.sem:
            proxy = {
                "http": f"http://{selected_proxy}",
                "https": f"http://{selected_proxy}"
            }
            boundary = "WebKitFormBoundary" + ''.join(
                secrets.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') for _ in range(16))
            header = {'content-type': f'multipart/form-data; boundary=----{boundary}'}
            data = f'------{boundary}\r\nContent-Disposition: form-data; name="FLUJOPAGOGW"\r\n\r\nPFPHM\r\n------{boundary}\r\nContent-Disposition: form-data; name="FLUJOPAGO"\r\n\r\n10002\r\n------{boundary}\r\nContent-Disposition: form-data; name="ex"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="paramLista"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="action"\r\n\r\ndespliegue_personal\r\n------{boundary}\r\nContent-Disposition: form-data; name="campos_borrar"\r\n\r\nCLACO_NUMERO\r\n------{boundary}\r\nContent-Disposition: form-data; name="operacion"\r\n\r\nAdicionar\r\n------{boundary}\r\nContent-Disposition: form-data; name="url_modal"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="id_objeto"\r\n\r\n10002\r\n------{boundary}\r\nContent-Disposition: form-data; name="valor_llave"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="parametros_padre"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="mensaje_error"\r\n\r\nDebe asignar a un responsable para la actividad a seguir\r\n------{boundary}\r\nContent-Disposition: form-data; name="go"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="preguardar"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="confGuardaComo"\r\n\r\nSeguro que desea duplicar este registro\r\n------{boundary}\r\nContent-Disposition: form-data; name="modifi_detalle"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="nombre_campo"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="latitud"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="longitud"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="enviarForm"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="autoguardar"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="guion_encuesta"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="clase"\r\n\r\nvistasclaro\r\n------{boundary}\r\nContent-Disposition: form-data; name="metodo"\r\n\r\nconfirmacion\r\n------{boundary}\r\nContent-Disposition: form-data; name="empresa"\r\n\r\nclaro\r\n------{boundary}\r\nContent-Disposition: form-data; name="NumeroCelular"\r\n\r\n{num}\r\n------{boundary}\r\nContent-Disposition: form-data; name="CLACO_NUMERO"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="NRO_CUENTA"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="TIPO_TRANS"\r\n\r\n2\r\n------{boundary}\r\nContent-Disposition: form-data; name="USRIO_NUMERO"\r\n\r\n1\r\n------{boundary}\r\nContent-Disposition: form-data; name="IPTRANSACCION"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="TIPO_TRANS_ORIG"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="FECHA_INICIO"\r\n\r\n2024-07-24 23:46\r\n------{boundary}\r\nContent-Disposition: form-data; name="NumeroIdentificacion"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="CodigoCliente"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="IdentificacionDeudor"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="OrigenPago"\r\n\r\n3\r\n------{boundary}\r\nContent-Disposition: form-data; name="SALDOPARCIAL"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="g-recaptcha-response"\r\n\r\ \r\n------{boundary}\r\nContent-Disposition: form-data; name="mySubmit_"\r\n\r\nContinuar\r\n------{boundary}--\r\n'
            url = 'https://portalpagos.claro.com.co/phrame.php'
            timeout = 20

            while True:
                try:
                    async with AsyncSession(impersonate="chrome99_android", headers=header, cookies=cookie,
                                            proxies=proxy,
                                            timeout=timeout) as s:
                        r = await s.post(url, data=data)
                    self.proxy_good.add(selected_proxy)
                    break
                except curl_cffi.requests.errors.RequestsError as e:
                    if "curl: (28)" in str(e):
                        cookie = await self.get_cookie(selected_proxy)

                    else:
                        #print(e)
                        continue

            if r.status_code == 200:
                i = self.get_info(r.text)
                if "Error" == i:
                    #print(num, "Error")
                    cok = await self.get_cookie(selected_proxy)
                    return await self.search_data(num, cok, selected_proxy)
                return num, self.get_info(r.text)

    async def search_data2(self, num, selected_proxy):
        """Placeholder for the search_data2 function."""
        # Implementar la lógica de search_data2 aquí
        async with self.sem:
            proxy = {
                "http": f"http://{selected_proxy}",
                "https": f"http://{selected_proxy}"
            }
            boundary = "WebKitFormBoundary" + ''.join(
                secrets.choice('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') for _ in range(16))
            header = {'content-type': f'multipart/form-data; boundary=----{boundary}'}
            url = 'https://portalpagos.claro.com.co/phrame.php?action=despliegue_personal&clase=VistasClaroComprobante&metodo=generarComprobante&empresa=claro'
            url2 = 'https://portalpagos.claro.com.co/phrame.php'
            # Define the data to be sent in the POST request
            data = f'------{boundary}\r\nContent-Disposition: form-data; name="FLUJOPAGOGW"\r\n\r\nPFPHM\r\n------{boundary}\r\nContent-Disposition: form-data; name="FLUJOPAGO"\r\n\r\n10002\r\n------{boundary}\r\nContent-Disposition: form-data; name="ex"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="paramLista"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="action"\r\n\r\ndespliegue_personal\r\n------{boundary}\r\nContent-Disposition: form-data; name="campos_borrar"\r\n\r\nCLACO_NUMERO\r\n------{boundary}\r\nContent-Disposition: form-data; name="operacion"\r\n\r\nAdicionar\r\n------{boundary}\r\nContent-Disposition: form-data; name="url_modal"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="id_objeto"\r\n\r\n10002\r\n------{boundary}\r\nContent-Disposition: form-data; name="valor_llave"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="parametros_padre"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="mensaje_error"\r\n\r\nDebe asignar a un responsable para la actividad a seguir\r\n------{boundary}\r\nContent-Disposition: form-data; name="go"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="preguardar"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="confGuardaComo"\r\n\r\nSeguro que desea duplicar este registro\r\n------{boundary}\r\nContent-Disposition: form-data; name="modifi_detalle"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="nombre_campo"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="latitud"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="longitud"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="enviarForm"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="autoguardar"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="guion_encuesta"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="clase"\r\n\r\nvistasclaro\r\n------{boundary}\r\nContent-Disposition: form-data; name="metodo"\r\n\r\nconfirmacion\r\n------{boundary}\r\nContent-Disposition: form-data; name="empresa"\r\n\r\nclaro\r\n------{boundary}\r\nContent-Disposition: form-data; name="NumeroCelular"\r\n\r\n{num}\r\n------{boundary}\r\nContent-Disposition: form-data; name="CLACO_NUMERO"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="NRO_CUENTA"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="TIPO_TRANS"\r\n\r\n2\r\n------{boundary}\r\nContent-Disposition: form-data; name="USRIO_NUMERO"\r\n\r\n1\r\n------{boundary}\r\nContent-Disposition: form-data; name="IPTRANSACCION"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="TIPO_TRANS_ORIG"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="FECHA_INICIO"\r\n\r\n2024-07-24 23:46\r\n------{boundary}\r\nContent-Disposition: form-data; name="NumeroIdentificacion"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="CodigoCliente"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="IdentificacionDeudor"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="OrigenPago"\r\n\r\n3\r\n------{boundary}\r\nContent-Disposition: form-data; name="SALDOPARCIAL"\r\n\r\n\r\n------{boundary}\r\nContent-Disposition: form-data; name="g-recaptcha-response"\r\n\r\ \r\n------{boundary}\r\nContent-Disposition: form-data; name="mySubmit_"\r\n\r\nContinuar\r\n------{boundary}--\r\n'

            while True:
                try:
                    async with AsyncSession(impersonate="chrome99_android", proxies=proxy) as s:
                        r = await s.get(url)
                        if r.status_code == 200:
                            r = await s.post(url2, data=data, headers=header)

                    break
                except curl_cffi.requests.errors.RequestsError as e:
                    if "curl: (28)" in str(e):
                        continue  # Retry on timeout
                    else:
                        #print(e)
                        continue  # Break on other errors

            if r.status_code == 200:
                info = self.get_info(r.text)
                if info == "Error":
                    cok = await self.get_cookie(selected_proxy)
                    return await self.search_data(num, cok, selected_proxy)
                self.proxy_good.add(selected_proxy)
                return num, info

    async def execute_main(self, num, cok, proxy):
        tasks = [asyncio.create_task(self.search_data2(i, proxy[n % len(proxy)])) for n, i in enumerate(num)]
        """tasks = [asyncio.create_task(search_data(i, cok[n % len(cok)], proxy[n % len(proxy)])) for n, i in enumerate(num)]"""
        num_ok, num_plan, num_change, num_check = [], [], [], []
        count = 0
        self.sublist = num
        for future in asyncio.as_completed(tasks):
            num2, info = await future
            self.num.append(num2)
            print(f"\r{Fore.GREEN}Processing: {count}/{len(num)}{Style.RESET_ALL}", end="")
            count += 1
            if "/" in info:
                num_plan.append(f"{num2} {info}")
            elif "No" in info or "Saldo" in info:
                num_change.append(num2)
            elif "$" in info:
                num_ok.append(f"{num2} {info.replace('$', '')}")
            else:
                print(num2, info)
                num_check.append(num2)
        print(f"\r{Fore.GREEN}Processing: {count}/{len(num)}{Style.RESET_ALL}", end="")
        print(len(num_ok), len(num_plan), len(num_change), len(num_check))
        self.stats['b'] += len(num_ok)
        self.stats['m'] += len(num_plan)
        self.stats['c'] += len(num_change)
        self.stats['r'] += len(num_check)

        self.write_file('file.txt', num_ok)
        self.write_file('file2.txt', num_plan)
        self.write_file('file3.txt', num_change)
        self.write_file('file4.txt', num_check)

    async def process(self):
        num = self.read_file('num.txt')
        proxy_list = self.read_file('proxies.txt')
        #proxies_formateados = [self.format_proxy(proxy) for proxy in proxy_list]
        proxies_formateados = proxy_list
        self.proxylist = proxies_formateados
        sublistas = [num[i:i + len(proxy_list)] for i in range(0, len(num), len(proxy_list))]

        cok = None
        t1 = time.perf_counter()

        for sublist in sublistas:
            t2 = time.perf_counter()
            async with asyncio.TaskGroup() as tg:
                tg.create_task(self.execute_main(sublist, cok, proxies_formateados))

            print(f"Time for sublist: {time.perf_counter() - t2} seconds")
            print(self.stats)

        print(f"Total time: {time.perf_counter() - t1} seconds")

def g(g:Generator):
    time.sleep(60)
    print(obtener_diferencia(g.sublist,g.num))
    print(obtener_diferencia(g.proxylist, g.proxy_good))
# Ejecución del script principal
if __name__ == "__main__":
    processor = Generator()
    t = threading.Thread(target=g, args=(processor,))
    t.start()
    asyncio.run(processor.process())
    t.join()