import mimetypes
from typing import Dict, Optional, TypedDict, Union

from literalai.observability.step import Attachment

from literalai.api import gql


def create_attachment_helper(
    step_id: str,
    thread_id: Optional[str] = None,
    id: Optional[str] = None,
    metadata: Optional[Dict] = None,
    mime: Optional[str] = None,
    name: Optional[str] = None,
    object_key: Optional[str] = None,
    url: Optional[str] = None,
    content: Optional[Union[bytes, str]] = None,
    path: Optional[str] = None,
):
    if not content and not url and not path:
        raise Exception("Either content, path or attachment url must be provided")

    if content and path:
        raise Exception("Only one of content and path must be provided")

    if (content and url) or (path and url):
        raise Exception("Only one of content, path and attachment url must be provided")

    if path:
        # TODO: if attachment.mime is text, we could read as text?
        with open(path, "rb") as f:
            content = f.read()
        if not name:
            name = path.split("/")[-1]
        if not mime:
            mime, _ = mimetypes.guess_type(path)
            mime = mime or "application/octet-stream"

    if not name:
        raise Exception("Attachment name must be provided")

    variables = {
        "metadata": metadata,
        "mime": mime,
        "name": name,
        "objectKey": object_key,
        "stepId": step_id,
        "threadId": thread_id,
        "url": url,
        "id": id,
    }

    description = "create attachment"

    def process_response(response):
        return Attachment.from_dict(response["data"]["createAttachment"])

    return gql.CREATE_ATTACHMENT, description, variables, content, process_response


class AttachmentUpload(TypedDict, total=False):
    metadata: Optional[Dict]
    name: Optional[str]
    mime: Optional[str]
    objectKey: Optional[str]
    url: Optional[str]


def update_attachment_helper(id: str, update_params: AttachmentUpload):
    variables = {"id": id, **update_params}

    def process_response(response):
        return Attachment.from_dict(response["data"]["updateAttachment"])

    description = "update attachment"

    return gql.UPDATE_ATTACHMENT, description, variables, process_response


def get_attachment_helper(id: str):
    variables = {"id": id}

    def process_response(response):
        attachment = response["data"]["attachment"]
        return Attachment.from_dict(attachment) if attachment else None

    description = "get attachment"

    return gql.GET_ATTACHMENT, description, variables, process_response


def delete_attachment_helper(id: str):
    variables = {"id": id}

    def process_response(response):
        return response["data"]["deleteAttachment"]

    description = "delete attachment"

    return gql.DELETE_ATTACHMENT, description, variables, process_response
