from datetime import datetime, timezone
import json
import logging
import locale
from uuid import uuid4
from typing import Any
from .errors import CookieExpiredError
from .errors import VerificationError


__common_error_support_info = "Incase you have no idea on how to get the cookies check the documentation at - \
    https://github.com/Simatwa/WebChatGPT"


headers = request_headers = {
    "Accept": "text/event-stream",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "en-US,en;q=0.5",
    # "Alt-Used": "chat.openai.com",
    "Connection": "keep-alive",
    "Content-Type": "application/json",
    "Host": "chat.openai.com",
    "Origin": "https://chat.openai.com",
    "Referer": "https://chat.openai.com/",
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0",
    "OAI-Language": locale.getlocale()[0].replace("_", "-"),
}

init_headers = {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "en-US,en;q=0.5",
    "User-Agent": headers["User-Agent"],
    "Connection": "keep-alive",
    "Sec-Fetch-Site": "none",
}

response_example = {
    "message": {
        "id": "b9ce2438-a00a-4c1e-9487-3abba1xxxxx",
        "author": {"role": "assistant", "name": None, "metadata": {}},
        "create_time": 1708178888.142936,
        "update_time": None,
        "content": {
            "content_type": "text",
            "parts": ["This is response generated by chatgpt"],
        },
        "status": "in_progress",
        "end_turn": None,
        "weight": 1.0,
        "metadata": {
            "citations": [],
            "gizmo_id": None,
            "message_type": "next",
            "model_slug": "text-davinci-002-render-sha",
            "parent_id": "13442586-492c-4d0e-95a8-032b6xxxxx",
        },
        "recipient": "all",
    },
    "conversation_id": "f5a118a5-e9b5-476c-ac12-e44ad77exxxx",
    "error": None,
}


def error_handler(
    exit_on_error: bool = False, default: Any = None, info: str = None, raise_err=False
):
    """Decorator for handling exceptions

    Args:
        exit_on_error (bool, optional): ``. Defaults to False.
        default (Any, optional): Return this incase of an exception. Defaults to None.
        info (str, optional): Message to be shown along with the exception details. Defaults to None.
        raise_err (bool, optional): Raise exception instead of logging it. Defaults to False.
    """

    def decorator(func):
        def main(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                if raise_err:  # Raise exception
                    if info:
                        raise Exception(info) from e
                    else:
                        raise Exception(e)
                else:
                    logging.error(
                        f"{e.args[1] if len(e.args) > 1 else str(e)} - {info}"
                    )
                if exit_on_error:
                    exit(1)
                return default

        return main

    return decorator  #


def get_request_headers_and_initialize_request(self) -> dict:
    """Generate Http request headers & append OAuth

    Returns:
        dict: Request headers
    """
    resp1 = self.session.get("https://chat.openai.com", headers=init_headers)
    resp1.raise_for_status()
    """
    resp = self.session.get(
        "https://chat.openai.com/api/auth/session",
        headers=request_headers,
    )
    #print(json.dumps(resp.json(), indent=4))
    """
    return headers


@error_handler(
    exit_on_error=True,
    raise_err=True,
    info="" + __common_error_support_info,
)
def get_cookies(path: str) -> dict:
    """Reads cookies and format them

    Args:
        path (str): Path to cookie file

    Returns:
        dict: Cookies sorted {name :  value}
    """
    resp = {}
    with open(path) as fh:
        for entry in json.load(fh):
            resp[entry["name"]] = entry["value"]
        return resp


def is_json(response: object, info: str = ""):
    """Checks whether the response is application/json formatted

    Args:
        response (object): `requests.get/post response`
        info (str): Data being fetched
    rtype : dict
    """
    content_type = response.headers.get("content-type")
    if not "application/json" in content_type:
        raise Exception(
            f"Failed to fetch {info} - ({response.status_code}, {response.reason}) `{content_type}` : \n {response.text}"
        )
    return response.json()


def current_timestamp():
    """Generates current timestamp in UTC
    rtype : str
    """
    current_time = datetime.now(timezone.utc)
    # Format the current time in the desired format with microseconds limited to 3 digits
    return current_time.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"


def generate_telemetry_payload(self: object):
    """Generates Telemeries - though not implemented in this script but it's good to be aware of.

    Args:
        self (object): ChatGPT class
    rtype : dict
    """
    headers = self.session.headers
    payload_template = {
        "batch": [
            {
                "timestamp": f"{current_timestamp()}",
                "integrations": {"Segment.io": True},
                "userId": f"{headers.get('ajs_user_id')}",
                "anonymousId": f"{headers.get('ajs_anonymous_id')}",
                "event": "Show Starter Prompts",
                "type": "track",
                "properties": {
                    "prompt_count": 4,
                    "prompt_type": "starter",
                    "titles": [entry["title"] for entry in self.prompt_library()],
                    "origin": "chat",
                    "openai_app": "API",
                },
                "context": {
                    "page": {
                        "path": "/",
                        "referrer": "",
                        "search": "",
                        "title": "ChatGPT",
                        "url": "https://chat.openai.com/",
                    },
                    "userAgent": self.session.headers["User-Agent"],
                    "locale": self.locale,
                    "library": {"name": "analytics.js", "version": "npm:next-1.56.0"},
                },
                # "messageId": "ajs-next-3154852a6626ae6a48a031e2506fexxx",
                "_metadata": {
                    "bundled": ["Segment.io"],
                    "unbundled": [],
                    "bundledIds": [],
                },
            }
        ],
        "sentAt": f"{current_timestamp()}",
    }


def generate_payload(self: object, prompt: str) -> dict:
    """Creates conversation payload

    Args:
        self (object): _

    Returns:
        dict: _description_
    """

    payload_template = {
        "action": "next",
        "messages": [
            {
                # "id": "aaa2921d-d8c9-4516-80bd-ed1eaxxxxx",
                "author": {"role": "user"},
                "content": {"content_type": "text", "parts": [prompt]},
                "metadata": {},
            }
        ],
        # "conversation_id": self.conversation_metadata["id"],
        # "parent_message_id": "5b45a98c-0871-48ed-895b-f36f188cxxxx",
        "model": self.model,
        "timezone_offset_min": -180,
        "suggestions": [],
        "history_and_training_disabled": self.disable_history_and_training,
        # "arkose_token": None,
        "conversation_mode": {"kind": "primary_assistant"},
        "force_paragen": False,
        "force_rate_limit": False,
    }

    if self.current_conversation_id:
        # Continuing conversation
        payload_template["conversation_id"] = self.current_conversation_id
    else:
        # Create new conversation
        payload_template["messages"][0]["id"] = "aaa2" + uuid4().__str__()[4:]
        payload_template["suggestions"] = [
            prompt["prompt"] for prompt in self.prompt_library()["items"]
        ]

    # print(json.dumps( payload_template,indent=4,))
    return payload_template


def get_message(response: dict) -> str:
    """Extracts generated message from the response

    Args:
        response (dict): `bot.ask` response

    Returns:
        str: Extracted message
    """
    # print(json.dumps(response,indent=4))
    assert isinstance(response, dict), "'response' should be of 'dict' data-type"
    return response["message"]["content"]["parts"][0]
