from __future__ import annotations

import json
from urllib.parse import quote

import httpx

GOOGLE_DRIVE_ENDPOINT = "https://www.googleapis.com/drive/v3"


def _escape_drive_query_value(value: str) -> str:
    return value.replace("\\", "\\\\").replace("'", "\\'")


async def resolve_or_create_drive_folder(
    client: httpx.AsyncClient,
    *,
    access_token: str,
    folder_reference: str,
) -> str:
    headers = {"Authorization": f"Bearer {access_token}"}
    normalized_reference = folder_reference.strip()
    if not normalized_reference:
        raise ValueError("Nome cartella Drive non valido.")

    if "/" not in normalized_reference:
        lookup_response = await client.get(
            f"{GOOGLE_DRIVE_ENDPOINT}/files/{quote(normalized_reference, safe='')}",
            headers=headers,
            params={"fields": "id, name, mimeType"},
        )
        if lookup_response.status_code == 200:
            payload = lookup_response.json()
            if payload.get("mimeType") != "application/vnd.google-apps.folder":
                raise ValueError("Il riferimento Drive esiste ma non punta a una cartella.")
            return str(payload["id"])

        if lookup_response.status_code not in {400, 403, 404}:
            lookup_response.raise_for_status()

    search_response = await client.get(
        f"{GOOGLE_DRIVE_ENDPOINT}/files",
        headers=headers,
        params={
            "q": (
                "mimeType = 'application/vnd.google-apps.folder' "
                f"and trashed = false and name = '{_escape_drive_query_value(normalized_reference)}'"
            ),
            "pageSize": 1,
            "orderBy": "createdTime",
            "fields": "files(id, name, mimeType, createdTime)",
        },
    )
    search_response.raise_for_status()
    files = search_response.json().get("files", [])
    if isinstance(files, list) and files:
        existing = files[0]
        if isinstance(existing, dict) and existing.get("id"):
            return str(existing["id"])

    create_response = await client.post(
        f"{GOOGLE_DRIVE_ENDPOINT}/files",
        headers=headers,
        params={"fields": "id, name"},
        json={"name": normalized_reference, "mimeType": "application/vnd.google-apps.folder"},
    )
    create_response.raise_for_status()
    return str(create_response.json()["id"])


async def upload_binary_file_to_drive(
    client: httpx.AsyncClient,
    *,
    access_token: str,
    filename: str,
    mime_type: str,
    raw_bytes: bytes,
    folder_reference: str,
) -> dict[str, str]:
    folder_id = await resolve_or_create_drive_folder(
        client,
        access_token=access_token,
        folder_reference=folder_reference,
    )
    metadata = {"name": filename, "parents": [folder_id]}
    files = {
        "metadata": ("metadata", json.dumps(metadata), "application/json; charset=UTF-8"),
        "file": (filename, raw_bytes, mime_type),
    }
    response = await client.post(
        "https://www.googleapis.com/upload/drive/v3/files",
        headers={"Authorization": f"Bearer {access_token}"},
        params={"uploadType": "multipart", "fields": "id, webViewLink, parents"},
        files=files,
    )
    response.raise_for_status()
    payload = response.json()
    return {
        "file_id": str(payload["id"]),
        "web_url": str(payload.get("webViewLink") or f"https://drive.google.com/file/d/{payload['id']}/view"),
        "folder_id": folder_id,
    }
