import json
import ssl
from utils.logger import logger
from typing import Dict, List
from aiohttp import ClientSession, ClientError, FormData, TCPConnector


async def requestGET(
    url: str, headers: dict = None, params: dict = None, verify_ssl: bool = True
):
    """GET запрос к url, возвращает результат запроса в формате json

    Параметры:
    - url: адрес, к которому будет выполнен GET запрос
    - headers: заголовки запроса, словарь, где ключи - имена заголовков, а значения - их значения
    - params: параметры запроса, словарь, где ключи - имена параметров, а значения - их значения

    Возвращается:
    - результат запроса в формате json
    """
    from utils import answer

    ssl_context = None

    if not verify_ssl:
        ssl_context = ssl.create_default_context()
        ssl_context.check_hostname = False
        ssl_context.verify_mode = ssl.CERT_NONE

    try:
        connector = TCPConnector(ssl=ssl_context)
        async with ClientSession(connector=connector) as session:
            async with session.get(url, params=params, headers=headers) as response:
                response.raise_for_status()  # Проверка на успешность выполнения запроса
                data = await response.json()
                return answer(data=data)
    except ClientError as e:
        logger.error(f"Request failed: {e}")
        return answer(success=False, message=str(e))


async def requestPOST(
    url: str,
    headers: dict = None,
    json: dict = None,
    **kwargs,
):
    """POST запрос к url, возвращает результат запроса в формате json

    Параметры:
    - url: адрес, к которому будет выполнен POST запрос
    - headers: заголовки запроса, словарь, где ключи - имена заголовков, а значения - их значения
    - json: данные, которые будут отправлены в теле запроса, в формате json
    - **kwargs: необязательные параметры, передаваемые в метод request

    Возвращается:
    - результат запроса в формате json
    """
    try:
        async with ClientSession() as session:
            async with session.post(
                url, json=json, headers=headers, **kwargs
            ) as response:
                try:
                    responseJson = await response.json()
                    logger.warning(responseJson)
                except:
                    logger.error("Не удалось распарсить ответ сервера")
                response.raise_for_status()
                try:
                    return await response.json()
                except:
                    return {"status": "OK"}
    except ClientError as e:
        logger.error(f"Request failed: {e}")
        return None


async def requestPOSTMultipart(
    url: str,
    headers: dict,
    meta: dict,
    files: List[Dict],
    verify_ssl: bool = True,
):
    """
    files: [
        {
            "field": "file0",
            "path": Path("document.pdf"),
            "content_type": "application/pdf",
        },
        ...
    ]
    """

    form = FormData()

    # meta part (JSON)
    form.add_field(
        name="meta",
        value=json.dumps(meta, ensure_ascii=False),
        content_type="application/json; charset=utf-8",
    )

    # file parts
    for file in files:
        form.add_field(
            name=file["field"],
            value=file["path"].read_bytes(),
            filename=file["path"].name,
            content_type=file["content_type"],
        )

    try:
        async with ClientSession() as session:
            async with session.post(
                url,
                data=form,
                headers=headers,
                ssl=verify_ssl,
            ) as response:
                # try:
                #     responseJson = await response.json()
                #     logger.warning(responseJson)
                # except:
                #     logger.error("Не удалось распарсить ответ сервера")
                response.raise_for_status()
                try:
                    return await response.json()
                except Exception:
                    return {"status": "OK"}

    except ClientError as e:
        logger.error(f"Request failed: {e}")
        return None


async def requestPATCH(
    url: str,
    headers: dict = None,
    json: dict = None,
    **kwargs,
):
    """PATCH запрос к url, возвращает результат запроса в формате json

    Параметры:
    - url: адрес, к которому будет выполнен PATCH запрос
    - headers: заголовки запроса, словарь, где ключи - имена заголовков, а значения - их значения
    - json: данные, которые будут отправлены в теле запроса, в формате json
    - **kwargs: необязательные параметры, передаваемые в метод request

    Возвращается:
    - результат запроса в формате json
    """
    try:
        async with ClientSession() as session:
            async with session.patch(
                url, json=json, headers=headers, **kwargs
            ) as response:
                response.raise_for_status()
                try:
                    return await response.json()
                except:
                    return {"status": "OK"}
    except ClientError as e:
        logger.error(f"Request failed: {e}")
        return None


async def requestDELETE(url: str, headers: dict = None, json: dict = None):
    """
    DELETE запрос к url, возвращает результат запроса в формате json

    Параметры:
    - url: адрес, к которому будет выполнен DELETE запрос
    - headers: заголовки запроса, словарь, где ключи - имена заголовков, а значения - их значения
    - json: данные, которые будут отправлены в теле запроса, в формате json

    Возвращается:
    - результат запроса в формате json
    """
    try:
        async with ClientSession() as session:
            async with session.delete(url, headers=headers, json=json) as response:
                response.raise_for_status()
                return await response.json()
    except ClientError as e:
        logger.error(f"Request failed: {e}")
        return None
