import calendar

import logging

import os

import random

import string

import uuid

from datetime import timedelta, datetime

from rest_framework.response import Response

import requests

import aiohttp

from django.conf import settings

from django.utils import timezone

import json

from Apps.Providers import models

from Apps.Providers.models import ServiceUser

from Apps.Providers.models import Provider as ProviderModel

from requests.auth import HTTPBasicAuth

logger = logging.getLogger(name)

def subtract_months(dt, months):

month = dt.month - months

year = dt.year + month // 12

month = month % 12

if month == 0:

month = 12

year -= 1

day = min(dt.day, calendar.monthrange(year, month)[1])

return dt.replace(year=year, month=month, day=day)

def username_generator():

characters = string.ascii_letters + string.digits + '_'

username_length = random.randint(8, 20)
username = ''.join(random.choices(characters, k=username_length))
return username
class Provider:

def init(self, user, provider_id, service_type, region=None, ip_number=None):

self.user = user

self.provider_id = provider_id

self.service_type = service_type or 'residential'

self.region = region

self.ip_number = ip_number

def buy_proxy(self, traffic):
    raise NotImplementedError("This method should be implemented by subclasses")

def get_bandwith(self, provider_name, service_type='residential', plan_id=None, sub_user=None, package_key=None,
                 username=None):
    raise NotImplementedError("This method should be implemented by subclasses")

def make_request(self, url, data=None, auth=None, method='post'):
    """Utility method to handle HTTP requests and error handling."""
    try:
        if method == 'post':
            response = requests.post(url, headers=settings.HEADER, data=data, auth=auth)
        else:
            response = requests.get(url, headers=settings.HEADER, auth=auth)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        return {'error': str(e)}

def read_json_file(self, file_path):
    """Utility method to read a JSON file and handle errors."""
    try:
        with open(file_path, 'r', encoding='utf-8') as json_file:
            return json.load(json_file)
    except FileNotFoundError:
        return {'error': 'File not found', 'status': 404}
    except json.JSONDecodeError:
        return {'error': 'Error decoding JSON', 'status': 500}

def handle_request(self, service_name, request, **kwargs):
    if not request.user.is_authenticated:
        return Response(status=400, data={'message': 'You need to be authorized'})

    file_name = 'geo-proxy-seller-min.json' if service_name == 'proxy-seller' else 'geo-proxy-drop.json'
    file_path = os.path.join(settings.BASE_DIR, 'Apps', 'Providers', 'data', file_name)

    file_data = self.read_json_file(file_path)
    if 'error' in file_data:
        return Response(status=file_data['status'], data={'message': file_data['error']})

    return Response(status=200, data=file_data)

def get_credentials(self, service_user):
    return {"login": service_user.username, "password": service_user.password}
class LightningProvider(Provider):

ISP_URL = "https://resell.lightningproxies.net/api/getplan/isp"

INFO_BASE_URL = "https://resell.lightningproxies.net/api/info/"

BASE_URL = 'https://resell.lightningproxies.net/api'

def buy_proxy(self, traffic):
    service_user = ServiceUser.objects.filter(user=self.user, provider_id=self.provider_id,
                                              service_type=self.service_type)
    logger.info(f"{service_user} query service user {traffic} {self.user} {self.provider_id} {self.service_type}")

    if service_user.exists():
        service_user = service_user.first()
        if service_user.service_type == 'residential':
            self._handle_residential(service_user, traffic)
        elif service_user.service_type == 'isp':
            self._handle_isp(service_user, traffic)
    else:
        self._handle_new_user(traffic)

def _handle_residential(self, service_user, traffic):
    logger.info('request to lightning')
    url_add_plan = f"https://resell.lightningproxies.net/api/add/{service_user.plan_id}/{traffic}"
    resulting = requests.post(url_add_plan, headers=settings.HEADER).json()
    logger.info(f"{resulting}")
    exp_date = requests.get(f"{self.INFO_BASE_URL}{service_user.plan_id}", headers=settings.HEADER).json()['expiration_date']
    service_user.current_period_end = exp_date
    service_user.traffic = (service_user.traffic or 0) + traffic * 1000
    service_user.save()
    logger.info(f"{service_user} saving existing service user")
    self.user.save()

def _handle_isp(self, service_user, traffic):
    data = {"ip": (None, self.ip_number), "region": (None, self.region)}
    isp_result = requests.post(self.ISP_URL, files=data, headers=settings.HEADER).json()['PlanID']
    self.user.plan_id = isp_result
    exp_date = requests.get(f"{self.INFO_BASE_URL}{isp_result}", headers=settings.HEADER).json()['expiration_date']
    new_date = subtract_months(datetime.strptime(exp_date, "%Y-%m-%dT%H:%M:%S.%fZ"), 2)
    self.user.plan_available_date = new_date
    self.user.save()

    ServiceUser.objects.create(
        user=self.user, traffic=traffic * 1000,
        current_period_end=self.user.plan_available_date, provider_id=self.provider_id,
        plan_id=self.user.plan_id, service_type=self.service_type, region=self.region, ip_number=self.ip_number
    )

def handle_request(self, country_code, state, **kwargs):
    if not country_code and not state:
        response = self.make_request(f'{self.BASE_URL}/getlist/country_list')
    elif country_code and not state:
        response = self.make_request(f'{self.BASE_URL}/getlist/state_list',
                                     data={"country_code": (None, country_code)})
    elif country_code and state:
        response = self.make_request(f'{self.BASE_URL}/getlist/city_list',
                                     data={"country_code": (None, country_code), "state": (None, state)})
    else:
        return Response(status=400, data={'message': 'Invalid input'})

    return Response(status=200, data=response)

def get_credentials(self, service_user):
    if not service_user.username:
        response = requests.get(
            f'https://resell.lightningproxies.net/api/plan/residential/read/{service_user.plan_id}',
            headers=settings.HEADER
        ).json()

        try:
            service_user.username = response['user']
            service_user.password = response['pass']
            service_user.save()
        except KeyError:
            logger.error(f"Invalid response received: {response}")
            return None
    return {"login": service_user.username, "password": service_user.password}

def _handle_new_user(self, traffic):
    if self.user.plan_id:
        self._extend_existing_plan(traffic)
    else:
        self._create_new_plan(traffic)

def _extend_existing_plan(self, traffic):
    logger.info(f"plan exists for user")
    url_add_plan = f"https://resell.lightningproxies.net/api/add/{self.user.plan_id}/{traffic}"
    requests.post(url_add_plan, headers=settings.HEADER).json()
    self.user.plan_available_date = (self.user.plan_available_date or timezone.now()) + timedelta(weeks=4)
    self.user.save()

def _create_new_plan(self, traffic):
    base_url_plans = "https://resell.lightningproxies.net/api/getplan/residential" if self.service_type == 'residential' else self.ISP_URL
    data = {"bandwidth": (None, traffic)} if self.service_type == 'residential' else {"ip": (None, self.ip_number),
                                                                                      "region": (None, self.region)}

    response = requests.post(base_url_plans, headers=settings.HEADER, files=data).json()
    plan_id = response['PlanID']
    exp_date = requests.get(f"{self.INFO_BASE_URL}{plan_id}", headers=settings.HEADER).json()['expiration_date']

    ServiceUser.objects.create(
        user=self.user, traffic=traffic * 1000,
        current_period_end=exp_date, provider_id=self.provider_id,
        plan_id=plan_id, service_type=self.service_type, region=self.region, ip_number=self.ip_number
    )

async def get_bandwith_async(self, plan_id, **kwargs):
    async with aiohttp.ClientSession() as session:
        try:
            async with session.get(
                    f'https://resell.lightningproxies.net/api/plan/residential/read/{plan_id}',
                    headers=settings.HEADER
            ) as response:
                response.raise_for_status()
                bandwidth_left = await response.json()
                lightning_gigabytes = bandwidth_left['bandwidthLeft'] * 1000
                return lightning_gigabytes
        except aiohttp.ClientError as e:
            logger.error(f"Error fetching bandwidth from Lightning: {e}")
            return None
class GeoNodeProvider(Provider):

GEO_NODE_URL = "https://app-api.geonode.com/api/reseller/user/create"

def buy_proxy(self, traffic):
    service_user = ServiceUser.objects.filter(user=self.user, provider_id=self.provider_id,
                                              service_type=self.service_type)
    traffic = traffic * 1000
    headers = settings.GEO_NODE_HEADER

    if service_user.exists():
        self._handle_existing_user(service_user.first(), traffic)
    else:
        self._create_new_user(traffic)

def handle_request(self, request, **kwargs):
    if not request.user.is_authenticated:
        return Response(status=400, data={'message': 'You need to be authorized'})

    service_user = ServiceUser.objects.filter(user=request.user, provider__service_name='geo_node').first()
    if not service_user:
        return Response(status=400, data={'message': 'Service user not found'})

    result = self.make_request(
        'https://monitor.geonode.com/services/geo-target/RESIDENTIAL-PREMIUM',
        auth=HTTPBasicAuth(service_user.username, service_user.password),
        method='get'
    )

    if 'error' in result:
        if '401' in result['error']:
            return Response(status=401, data={'message': 'Please wait, setup is in progress. Try again in a minute.'})
        return Response(status=400, data={'message': f"Error: {result['error']}"})

    return Response(status=200, data=result)

def _handle_existing_user(self, service_user, traffic):
    url_add = f"https://app-api.geonode.com/api/reseller/user/{service_user.sub_user_id}"
    data = {
        "subscription_status": "active",
        "traffic_limit": service_user.traffic + traffic,
        "password": service_user.password,
        "current_period_end": str(service_user.current_period_end + timedelta(days=30))
    }
    logger.info(f"geo service exists {data} sending this")
    result_add = requests.put(url_add, headers=settings.GEO_NODE_HEADER, json=data)
    logger.info(f"response from geo {result_add.json()}")
    if result_add.status_code == 200:
        logger.info('saving now')
        service_user.traffic += traffic
        service_user.current_period_end += timedelta(days=30)
        service_user.save()
    else:
        logger.info('traffic end')

def _create_new_user(self, traffic):
    username = username_generator()
    password = str(uuid.uuid4())
    data = {
        "email": self.user.email,
        "serviceType": "RESIDENTIAL-PREMIUM" if self.service_type == 'residential' else "SHARED-DATACENTER",
        "traffic_limit": traffic,
        "username": username,
        "password": password
    }
    result = requests.post(self.GEO_NODE_URL, headers=settings.GEO_NODE_HEADER, json=data)
    if result.status_code == 200:
        result_data = result.json().get('data')
        ServiceUser.objects.create(
            user=self.user, username=username, password=password, traffic=traffic,
            current_period_end=result_data['current_period_end'], provider_id=self.provider_id,
            sub_user_id=result_data['id'], service_type=self.service_type
        )
    else:
        logger.error(f"Failed: {result.json()}")

async def get_bandwith_async(self, sub_user, **kwargs):
    user_id = sub_user[0]
    traffic = sub_user[1]

    async with aiohttp.ClientSession() as session:
        try:
            async with session.get(
                    f'https://app-api.geonode.com/api/reseller/user/traffic/{user_id}',
                    headers=settings.GEO_NODE_HEADER
            ) as response:
                response.raise_for_status()
                result = await response.json()
                data = result.get('data', {})
                if not data:
                    return 0
                total_traffic = traffic * 1000000 - int(data.get('usageBandwidth', 0))
                return total_traffic / 1000000
        except aiohttp.ClientError as e:
            logger.error(f"Error fetching bandwidth from GeoNode: {e}")
            return None
class ProxyResellerProvider(Provider):

def buy_proxy(self, traffic):

service_user = ServiceUser.objects.filter(user=self.user, provider_id=self.provider_id,

service_type=self.service_type)

if service_user.exists():

self._handle_existing_user(service_user.first(), traffic)

else:

self._create_new_user(traffic)

def get_credentials(self, service_user):
    if not service_user.username:
        response = requests.put(
            f"{settings.RESELLER_PROXY_BASE_URL}/residentsubuser/list/tools?package_key={service_user.package_key}").json()

        user_data = response['data']

        try:
            service_user.username = user_data['login']
            service_user.password = user_data['password']
            service_user.save()
        except KeyError:
            logger.error(f"Invalid response received: {response}")
            return None
    return {"login": service_user.username, "password": service_user.password}

def _handle_existing_user(self, service_user, traffic):
    try:
        traffic *= 1000
        response = requests.get(f"{settings.RESELLER_PROXY_BASE_URL}/residentsubuser/packages")
        response.raise_for_status()

        all_packages = response.json()

        if all_packages.get('status') != 'success':
            logger.error(f"Failed to fetch packages: {all_packages}")
            return

        for tariff in all_packages.get('data', []):
            if tariff.get('package_key') == service_user.package_key:
                logger.info(f'Package key found: {service_user.package_key}')

                traffic += tariff.get('traffic_limit', 0) / 1000000
                expired_at = timezone.now() + timedelta(weeks=4)

                data = {
                    "expired_at": f"{expired_at.day}.{expired_at.month}.{expired_at.year}",
                    "is_active": "true",
                    "traffic_limit": traffic * 1000,
                    "package_key": service_user.package_key
                }

                update_response = requests.post(f"{settings.RESELLER_PROXY_BASE_URL}/residentsubuser/update",
                                                data=data)
                update_response.raise_for_status()
                update_result = update_response.json()

                if update_result.get('status') == 'success':
                    result_data = update_result.get('data', {})
                    service_user.traffic = result_data.get('traffic_limit', service_user.traffic) // 1000000
                    service_user.current_period_end = result_data.get('expired_at', {}).get('date',
                                                                                            service_user.current_period_end)
                    service_user.save()
                else:
                    error_message = update_result.get('errors', [{'message': 'Unknown error'}])[0].get('message')
                    logger.error(f"Failed to update service user: {update_result}")
                    raise ValueError(f"Update failed: {error_message}")
    except requests.RequestException as e:
        logger.error(f"Request failed: {e}")
        raise ValueError("Failed to communicate with the reseller service")
    except Exception as e:
        logger.error(f"Unexpected error: {e}")
        raise ValueError("An unexpected error occurred while updating the service user")

def _create_new_user(self, traffic):
    try:
        expired_at = timezone.now() + timedelta(weeks=4)
        traffic *= 1000000000

        data = {
            "rotation": -1,
            "traffic_limit": traffic,
            "expired_at": f"{expired_at.day}.{expired_at.month}.{expired_at.year}",
            "is_link_date": False
        }

        response = requests.post(f"{settings.RESELLER_PROXY_BASE_URL}/residentsubuser/create", data=data)
        response.raise_for_status()

        request_result = response.json()

        if request_result.get('status') == 'success':
            result_data = request_result.get('data', {})
            package_key = result_data.get('package_key')

            ServiceUser.objects.create(
                user=self.user,
                traffic=result_data.get('traffic_limit', traffic) // 1000000,
                current_period_end=result_data.get('expired_at', {}).get('date'),
                provider_id=self.provider_id,
                package_key=package_key,
                service_type=self.service_type
            )
            logger.info(f"ServiceUser created successfully with package key: {package_key}")
        else:
            logger.error(f"Failed to create new user: {request_result}")

    except requests.RequestException as e:
        logger.error(f"Request to create new user failed: {e}")
    except Exception as e:
        logger.error(f"Unexpected error occurred while creating new user: {e}")

async def get_bandwith_async(self, package_key, **kwargs):
    async with aiohttp.ClientSession() as session:
        try:
            async with session.get(
                    f'{settings.RESELLER_PROXY_BASE_URL}/residentsubuser/packages'
            ) as response:
                response.raise_for_status()
                result = await response.json()
                data = result.get('data', {})
                if not data:
                    return 0
                for item in data:
                    if item['package_key'] == package_key:
                        return item['traffic_left'] / 1000000
        except aiohttp.ClientError as e:
            logger.error(f"Error fetching bandwidth from ProxySeller: {e}")
            return None
class ProxyDropProviderBase(Provider):

service_type = None  # To be defined in subclasses

def buy_proxy(self, traffic):
    service_type = models.Provider.objects.filter(id=self.provider_id).first().service_name
    service_user = ServiceUser.objects.filter(user=self.user, provider_id=self.provider_id,
                                              service_type=self.service_type)
    if service_user.exists():
        self._handle_existing_user(service_user.first(), traffic)
    else:
        self._create_new_user(traffic)

def _get_category_id(self, category_name):
    response = requests.post(f"{settings.DROP_PROXY_BASE_URL}/categories",
                             headers=settings.DROP_PROXY_HEADER,
                             params=settings.DROP_PROXY_PARAMS_GET)
    response.raise_for_status()
    categories = response.json()

    for key, value in categories.items():
        if value.get('name') == category_name:
            return value.get('id')
    logger.warning(f"Category '{category_name}' not found.")
    return None

def _get_product_id(self, category_id, product_name):
    response = requests.post(f"{settings.DROP_PROXY_BASE_URL}/goods",
                             headers=settings.DROP_PROXY_HEADER,
                             params=settings.DROP_PROXY_PARAMS_GET)
    response.raise_for_status()
    goods = response.json().get('goods', {})

    for item in goods.values():
        if item.get('id_cat') == category_id and item.get('name').replace(' ', '') == product_name:
            return item.get('id')
    logger.warning(f"Product '{product_name}' not found in category ID {category_id}.")
    return None

def _create_order(self, product_id):
    data = settings.DROP_PROXY_PARAMS_ORDER.copy()
    data['type'] = product_id
    data['count'] = 1

    response = requests.post(f"{settings.DROP_PROXY_BASE_URL}/createorder",
                             headers=settings.DROP_PROXY_HEADER,
                             data=data)
    response.raise_for_status()
    order_result = response.json()
    if order_result.get('ok') == 'TRUE':
        return order_result.get('invoice')
    logger.warning("Failed to create order.")
    raise ValueError(f"Failed to create order")

def _pay_order(self, invoice):
    response = requests.post(f"{settings.DROP_PROXY_BASE_URL}/paybalance/{invoice}",
                             headers=settings.DROP_PROXY_HEADER,
                             data=settings.DROP_PROXY_DATA_PAY)
    response.raise_for_status()
    pay_result = response.json()

    if pay_result.get('status') == 'ok':
        return pay_result.get('invoice')
    logger.warning(f"Failed to pay for order with invoice {invoice}.")
    return None

def _download_credentials(self, invoice):
    response = requests.post(f"{settings.DROP_PROXY_BASE_URL}/downloadtxt/{invoice}",
                             headers=settings.DROP_PROXY_HEADER)
    response.raise_for_status()
    file_content = response.text

    lines = file_content.split(';')
    login, password, coupon = None, None, None

    for line in lines:
        if 'LOGIN' in line:
            login = line.split(':')[1].strip()
        elif 'PASSWORD' in line:
            password = line.split(':')[1].strip()
        elif 'Your coupon' in line:
            coupon = line.split(':')[1].strip()

    if (login and password) or coupon:
        return login, password, coupon
    logger.warning("Failed to extract LOGIN and PASSWORD or COUPON from file content.")
    return None, None, None

def _create_new_user(self, traffic):
    try:
        expired_at = timezone.now() + timedelta(weeks=4)
        category_name = 'Резидентские Прокси IPV4'
        product_name = self._get_product_name(traffic)

        category_id = self._get_category_id(category_name)
        if not category_id:
            return

        product_id = self._get_product_id(category_id, product_name)
        if not product_id:
            return

        invoice = self._create_order(product_id)
        if not invoice:
            raise ValueError(f"Failed to create order")

        paid_invoice = self._pay_order(invoice)
        if not paid_invoice:
            return

        login, password, coupon = self._download_credentials(paid_invoice)
        if login and password:
            ServiceUser.objects.create(
                user=self.user,
                traffic=traffic * 1000,
                current_period_end=expired_at,
                provider_id=self.provider_id,
                service_type=self.service_type,
                username=login,
                password=password
            )
            logger.info("ServiceUser created successfully.")
        else:
            logger.warning("Failed to create ServiceUser due to missing credentials.")

    except requests.RequestException as e:
        logger.error(f"Request to create new user failed: {e}")
    except ValueError as e:
        logger.error(f"In except: {e}")
        raise ValueError(e)
    except Exception as e:
        logger.error(f"Unexpected error occurred while creating new user: {e}")

def _handle_existing_user(self, service_user, traffic):
    try:
        category_name = 'Продление прокси'
        product_name = self._get_renewal_product_name(traffic)

        category_id = self._get_category_id(category_name)
        if not category_id:
            return

        product_id = self._get_product_id(category_id, product_name)
        if not product_id:
            return

        invoice = self._create_order(product_id)
        if not invoice:
            raise ValueError(f"Failed to create order")

        paid_invoice = self._pay_order(invoice)
        if not paid_invoice:
            return

        login, password, coupon = self._download_credentials(paid_invoice)
        if coupon:
            response = requests.get(
                f'http://64.7.198.94/api/sub-account/{service_user.username}/refill/{coupon}/v6r890YmOUuzLX8Lw5v6c98enZROmwFomEfDenuckfV87ITgcyT5PCVnLkT8')
            response.raise_for_status()
            service_user.traffic += traffic * 1000

            service_user.current_period_end = timezone.now() + timedelta(weeks=4)
            service_user.save()
            logger.info("ServiceUser updated successfully.")
        else:
            logger.warning("Failed to update ServiceUser due to missing credentials.")
    except requests.RequestException as e:
        logger.error(f"Request to create new user failed: {e}")
    except ValueError as e:
        logger.error(f"In except: {e}")
        raise ValueError(e)
    except Exception as e:
        logger.error(f"Unexpected error occurred while creating new user: {e}")

def _get_product_name(self, traffic):
    raise NotImplementedError("Subclasses should implement this method to return the product name")

def _get_renewal_product_name(self, traffic):
    raise NotImplementedError("Subclasses should implement this method to return the renewal product name")

async def get_bandwith_async(self, username, **kwargs):
    async with aiohttp.ClientSession() as session:
        try:
            async with session.get(
                    f'http://64.7.198.94/api/sub-account/{username}/v6r890YmOUuzLX8Lw5v6c98enZROmwFomEfDenuckfV87ITgcyT5PCVnLkT8'
            ) as response:
                response.raise_for_status()
                text_response = await response.text()
                result = json.loads(text_response)
                bandWidth = result.get('bandWidth')
                bandWidthLimit = result.get('bandWidthLimit')
                if not bandWidthLimit:
                    return 0
                return (float(bandWidthLimit) - float(bandWidth)) * 1000
        except aiohttp.ClientError as e:
            logger.error(f"Error fetching bandwidth from ProxyDrop: {e}")
            return None
class ProxyDropProvider1(ProxyDropProviderBase):

service_type = 'proxy-drop1'

def _get_product_name(self, traffic):
    return f"ПУЛ№1РезидентныеПроксиIPV4-{traffic}GBТрафика(ПУЛ100М)[SOCKS5/HTTP]"

def _get_renewal_product_name(self, traffic):
    return f"ПУЛ№1Купоннапродлениепрокси+{traffic}ГБтрафика"
class ProxyDropProvider2(ProxyDropProviderBase):

service_type = 'proxy-drop2'

def _get_product_name(self, traffic):
    return f"ПУЛ№2РезидентныеПроксиIPV4-{traffic}GBТрафика(ПУЛ120М)[SOCKS5/HTTP]"

def _get_renewal_product_name(self, traffic):
    return f"ПУЛ№2Купоннапродлениепрокси+{traffic}ГБтрафика"
class AllProviders(Provider):

def init(self, user, provider_id, service_type, region=None, ip_number=None):

super().init(user, provider_id, service_type, region, ip_number)

# Инициализация всех провайдеров

provider_id_geo = ProviderModel.objects.get(service_name='geo_node').id

provider_id_light = ProviderModel.objects.get(service_name='lightning').id

provider_id_reseller = ProviderModel.objects.get(service_name='proxy-seller').id

provider_id_proxydr1 = ProviderModel.objects.get(service_name='proxy-drop1').id

provider_id_proxydr2 = ProviderModel.objects.get(service_name='proxy-drop2').id

if not provider_id_geo or not provider_id_light or not provider_id_reseller or not provider_id_proxydr1 or not provider_id_proxydr2:

raise Exception('Wrong id')

self.geo_node_provider = GeoNodeProvider(user, provider_id_geo, service_type, region, ip_number)

self.lightning_provider = LightningProvider(user, provider_id_light, service_type, region, ip_number)

self.proxy_reseller_provider = ProxyResellerProvider(user, provider_id_reseller, service_type, region,

ip_number)

self.proxy_drop_provider1 = ProxyDropProvider1(user, provider_id_proxydr1, service_type,

region=region,

ip_number=ip_number)

self.proxy_drop_provider2 = ProxyDropProvider2(user, provider_id_proxydr2, service_type,

region=region,

ip_number=ip_number)

def buy_proxy(self, traffic):
    self.geo_node_provider.buy_proxy(traffic)
    self.lightning_provider.buy_proxy(traffic)
    self.proxy_reseller_provider.buy_proxy(traffic)
    self.proxy_drop_provider1.buy_proxy(traffic)
    self.proxy_drop_provider2.buy_proxy(traffic)
provider_classes = {

"geo_node": GeoNodeProvider,

"lightning": LightningProvider,

"proxy-seller": ProxyResellerProvider,

"proxy-drop1": ProxyDropProvider1,

"proxy-drop2": ProxyDropProvider2,

"all_providers": AllProviders

}

Optimize code, change structure, etc. I need good handled oop code with models or products for residential and datacenter and isp products