import json
from abc import ABC, abstractmethod
from typing import Any, Generator

import aiohttp
import httpx
import requests
from requests.adapters import HTTPAdapter
from services.authorization import AAuthorization
from urllib3.util.retry import Retry
from utils.utils import parse_date

# SHARON_TRADING
# self.events_url: str = f'https://portal.zulily.com/v3/api/1/vendorApi/getEvents/true?dateEnd={self.end_date}+23:59:59&dateRangeType=past&dateStart={self.start_date}+00:00:00&page=1&size=100&sortDirection=DESC'
# PREMIUM EITHER           https://portal.zulily.com/v3/api/1/vendorApi/getEvents/true?dateEnd={self.end_date}+23:59:59&dateRangeType=past&dateStart={self.start_date}+00:00:00&page=1&size=100&sortDirection=DESC

# self.payments =

# fetch_sku_url = f'https://portal.zulily.com/v3/api/1/eventProducts/getEventProducts/{event_id}?liveEvent=false'
# fetch_sales_url = f'https://portal.zulily.com/v3/api/1/eventProducts/getEventProductsSale?liveEvent=false&eventId={event_id}'

# PREMIUMNATURE
# self.available = 'https://portal.zulily.com/v3/api/1/po/getPosBoosted?dateCreated=%5B%222016-01-01T00:00:00.000Z%22,)&size=500&sort=-dateCreated'
# self.payments = f'https://portal.zulily.com/v3/api/1/payment/getPayments?date_start={self.start_date}'

# current_url = f'https://portal.zulily.com/v3/api/1/po/getPoById/{po}'

HEADER = AAuthorization.authorization()


class RequestHandler(ABC):
    @abstractmethod
    def fetch(self):
        pass


class RequestTopShip(RequestHandler):
    """
    Class for handling http request to tophatter and shipstation API.
    """
    def __init__(self,
                 url: str,
                 header: dict or None = None,
                 data: dict or None = None):
        self.url = url
        self.header = header
        self.data = data
        self.retries = Retry(total=5,
                             backoff_factor=0.01,
                             status_forcelist=[500, 502, 503, 504])
        self.adapter = HTTPAdapter(max_retries=self.retries)

    def fetch(self) -> list[dict]:
        try:
            with requests.Session() as session:
                session.mount("https://", adapter=self.adapter)
                return self._load_json(
                    session.get(url=self.url,
                                data=self.data,
                                headers=self.header))

        except json.decoder.JSONDecodeError:
            self.fetch(self.url, data=self.data, headers=self.header)

    def _load_json(self, response: requests.Response) -> list[dict]:
        data = response.text.encode("utf-8")
        return json.loads(data)


class RequestAmazon(RequestHandler):
    """
    Class for handling requests to Connectbooks.
    """
    def __init__(self, payload: dict) -> list[dict]:
        self.payload = payload
        self.header = HEADER
        self.base_url = "https://webapi.connectbooks.com/api/reports/new/259"

    async def fetch(self) -> list[dict]:
        """
        Method for fetching sales from Connectbooks:
        """
        async with aiohttp.ClientSession() as session:
            async with session.post(self.base_url,
                                    headers=self.header,
                                    data=self.payload) as response:
                data = await response.json()
                return data.get("Data")


class RequestZulily(RequestHandler):
    def __init__(self,
                 start_date: str,
                 end_date: str,
                 authorization: str = None):
        self.start_date = start_date
        self.end_date = end_date
        self.authorization = {"Authorization": authorization}

        self.parsed_start = parse_date(self.start_date)
        self.parsed_end = parse_date(self.end_date)
        self.payments = f"https://portal.zulily.com/v3/api/1/payment/getPayments?date_start={self.start_date}"
        self.past_events = f"https://portal.zulily.com/v3/api/1/vendorApi/getEvents/true?dateEnd={self.end_date}+23:59:59&dateRangeType=past&dateStart={self.start_date}+00:00:00&page=1&size=100&sortDirection=DESC"
        self.purchase_orders_available = f"https://portal.zulily.com/v3/api/1/po/getPosBoosted?dateCreated=%5B%22{self.start_date}T00:00:00.000Z%22,)&size=500&sort=-dateCreated"

    async def fetch_past_events(self) -> Generator:
        response = await self.fetch(self.past_events)
        events = response.get("success").get("data")
        return (event.get("event_id") for event in events)

    async def get_current_event_data(self, event_id: str) -> tuple[list[dict]]:
        event_products_skus = f"https://portal.zulily.com/v3/api/1/eventProducts/getEventProducts/{event_id}?liveEvent=false"
        event_product_sales = f"https://portal.zulily.com/v3/api/1/eventProducts/getEventProductsSale?liveEvent=false&eventId={event_id}"

        products_skus = await self.fetch(event_products_skus)
        products_sales = await self.fetch(event_product_sales)

        return (products_skus.get("success"), products_sales.get("success"))

    async def purchase_orders(self):
        response = await self.fetch(self.purchase_orders_available)
        data = response.get("success").get("result")
        return (po.get("poId") for po in data
                if parse_date(po.get("dateCreated")) <= self.parsed_end)

    async def get_invoices(self):
        response = await self.fetch(self.payments)
        return response.get("success").get("item")

    async def fetch(self, url) -> Any:
        async with aiohttp.ClientSession() as session:
            async with session.get(url,
                                   headers=self.authorization) as response:
                return await response.json()

import json
from abc import ABC, abstractmethod
from typing import Any, Generator

import aiohttp
import httpx
import requests
from requests.adapters import HTTPAdapter
from services.authorization import AAuthorization
from urllib3.util.retry import Retry
from utils.utils import parse_date

# SHARON_TRADING
# self.events_url: str = f'https://portal.zulily.com/v3/api/1/vendorApi/getEvents/true?dateEnd={self.end_date}+23:59:59&dateRangeType=past&dateStart={self.start_date}+00:00:00&page=1&size=100&sortDirection=DESC'
# PREMIUM EITHER           https://portal.zulily.com/v3/api/1/vendorApi/getEvents/true?dateEnd={self.end_date}+23:59:59&dateRangeType=past&dateStart={self.start_date}+00:00:00&page=1&size=100&sortDirection=DESC

# self.payments =

# fetch_sku_url = f'https://portal.zulily.com/v3/api/1/eventProducts/getEventProducts/{event_id}?liveEvent=false'
# fetch_sales_url = f'https://portal.zulily.com/v3/api/1/eventProducts/getEventProductsSale?liveEvent=false&eventId={event_id}'

# PREMIUMNATURE
# self.available = 'https://portal.zulily.com/v3/api/1/po/getPosBoosted?dateCreated=%5B%222016-01-01T00:00:00.000Z%22,)&size=500&sort=-dateCreated'
# self.payments = f'https://portal.zulily.com/v3/api/1/payment/getPayments?date_start={self.start_date}'

# current_url = f'https://portal.zulily.com/v3/api/1/po/getPoById/{po}'

HEADER = AAuthorization.authorization()


class RequestHandler(ABC):
    @abstractmethod
    def fetch(self):
        pass


class RequestTopShip(RequestHandler):
    """
    Class for handling http request to tophatter and shipstation API.
    """
    def __init__(self,
                 url: str,
                 header: dict or None = None,
                 data: dict or None = None):
        self.url = url
        self.header = header
        self.data = data
        self.retries = Retry(total=5,
                             backoff_factor=0.01,
                             status_forcelist=[500, 502, 503, 504])
        self.adapter = HTTPAdapter(max_retries=self.retries)

    def fetch(self) -> list[dict]:
        try:
            with requests.Session() as session:
                session.mount("https://", adapter=self.adapter)
                return self._load_json(
                    session.get(url=self.url,
                                data=self.data,
                                headers=self.header))

        except json.decoder.JSONDecodeError:
            self.fetch(self.url, data=self.data, headers=self.header)

    def _load_json(self, response: requests.Response) -> list[dict]:
        data = response.text.encode("utf-8")
        return json.loads(data)


class RequestAmazon(RequestHandler):
    """
    Class for handling requests to Connectbooks.
    """
    def __init__(self, payload: dict) -> list[dict]:
        self.payload = payload
        self.header = HEADER
        self.base_url = "https://webapi.connectbooks.com/api/reports/new/259"

    async def fetch(self) -> list[dict]:
        """
        Method for fetching sales from Connectbooks:
        """
        async with aiohttp.ClientSession() as session:
            async with session.post(self.base_url,
                                    headers=self.header,
                                    data=self.payload) as response:
                data = await response.json()
                return data.get("Data")


class RequestZulily(RequestHandler):
    def __init__(self,
                 start_date: str,
                 end_date: str,
                 authorization: str = None):
        self.start_date = start_date
        self.end_date = end_date
        self.authorization = {"Authorization": authorization}

        self.parsed_start = parse_date(self.start_date)
        self.parsed_end = parse_date(self.end_date)
        self.payments = f"https://portal.zulily.com/v3/api/1/payment/getPayments?date_start={self.start_date}"
        self.past_events = f"https://portal.zulily.com/v3/api/1/vendorApi/getEvents/true?dateEnd={self.end_date}+23:59:59&dateRangeType=past&dateStart={self.start_date}+00:00:00&page=1&size=100&sortDirection=DESC"
        self.purchase_orders_available = f"https://portal.zulily.com/v3/api/1/po/getPosBoosted?dateCreated=%5B%22{self.start_date}T00:00:00.000Z%22,)&size=500&sort=-dateCreated"

    async def fetch_past_events(self) -> Generator:
        response = await self.fetch(self.past_events)
        events = response.get("success").get("data")
        return (event.get("event_id") for event in events)

    async def get_current_event_data(self, event_id: str) -> tuple[list[dict]]:
        event_products_skus = f"https://portal.zulily.com/v3/api/1/eventProducts/getEventProducts/{event_id}?liveEvent=false"
        event_product_sales = f"https://portal.zulily.com/v3/api/1/eventProducts/getEventProductsSale?liveEvent=false&eventId={event_id}"

        products_skus = await self.fetch(event_products_skus)
        products_sales = await self.fetch(event_product_sales)

        return (products_skus.get("success"), products_sales.get("success"))

    async def purchase_orders(self):
        response = await self.fetch(self.purchase_orders_available)
        data = response.get("success").get("result")
        return (po.get("poId") for po in data
                if parse_date(po.get("dateCreated")) <= self.parsed_end)

    async def get_invoices(self):
        response = await self.fetch(self.payments)
        return response.get("success").get("item")

    async def fetch(self, url) -> Any:
        async with aiohttp.ClientSession() as session:
            async with session.get(url,
                                   headers=self.authorization) as response:
                return await response.json()

# SHARON_TRADING # self.events_url: str = f'https://portal.zulily.com/v3/api/1/vendorApi/getEvents/true?dateEnd={self.end_date}+23:59:59&dateRangeType=past&dateStart={self.start_date}+00:00:00&page=1&size=100&sortDirection=DESC' # PREMIUM EITHER           https://portal.zulily.com/v3/api/1/vendorApi/getEvents/true?dateEnd={self.end_date}+23:59:59&dateRangeType=past&dateStart={self.start_date}+00:00:00&page=1&size=100&sortDirection=DESC # self.payments = # fetch_sku_url = f'https://portal.zulily.com/v3/api/1/eventProducts/getEventProducts/{event_id}?liveEvent=false' # fetch_sales_url = f'https://portal.zulily.com/v3/api/1/eventProducts/getEventProductsSale?liveEvent=false&eventId={event_id}' # PREMIUMNATURE # self.available = 'https://portal.zulily.com/v3/api/1/po/getPosBoosted?dateCreated=%5B%222016-01-01T00:00:00.000Z%22,)&size=500&sort=-dateCreated' # self.payments = f'https://portal.zulily.com/v3/api/1/payment/getPayments?date_start={self.start_date}' # current_url = f'https://portal.zulily.com/v3/api/1/po/getPoById/{po}' Class for handling http request to tophatter and shipstation API. Class for handling requests to Connectbooks. Method for fetching sales from Connectbooks: