"""Google Drive API v3 integration via raw httpx."""

import base64
import json

import httpx

from fliiq.runtime.google_auth import get_access_token

BASE_URL = "https://www.googleapis.com/drive/v3"
UPLOAD_URL = "https://www.googleapis.com/upload/drive/v3"

FILE_FIELDS = "id,name,mimeType,modifiedTime,size,parents,webViewLink"


async def handler(params: dict) -> dict:
    """Handle Google Drive operations."""
    action = params["action"]

    try:
        _, access_token = await get_access_token(params.get("account_email"))
        headers = {
            "Authorization": f"Bearer {access_token}",
            "Content-Type": "application/json",
        }

        async with httpx.AsyncClient(timeout=30) as client:
            if action == "list_files":
                return await _list_files(client, headers, params)
            elif action == "search_files":
                return await _search_files(client, headers, params)
            elif action == "get_metadata":
                return await _get_metadata(client, headers, params)
            elif action == "create_folder":
                return await _create_folder(client, headers, params)
            elif action == "upload_file":
                return await _upload_file(client, headers, params)
            elif action == "export_file":
                return await _export_file(client, headers, params)
            elif action == "delete_file":
                return await _delete_file(client, headers, params)
            else:
                return {
                    "success": False,
                    "message": f"Unknown action: {action}",
                    "data": {},
                }
    except ValueError:
        raise
    except httpx.HTTPStatusError as e:
        error_msg = f"Google Drive API error: {e.response.status_code}"
        try:
            error_data = e.response.json()
            if "error" in error_data:
                detail = error_data["error"]
                if isinstance(detail, dict):
                    error_msg += f" - {detail.get('message', '')}"
                else:
                    error_msg += f" - {detail}"
        except Exception:
            pass
        return {"success": False, "message": error_msg, "data": {}}
    except Exception as e:
        return {"success": False, "message": f"Error: {e}", "data": {}}


async def _list_files(
    client: httpx.AsyncClient, headers: dict, params: dict
) -> dict:
    """List files in a folder."""
    folder_id = params.get("folder_id", "root")
    max_results = params.get("max_results", 50)

    resp = await client.get(
        f"{BASE_URL}/files",
        headers=headers,
        params={
            "q": f"'{folder_id}' in parents and trashed = false",
            "fields": f"files({FILE_FIELDS})",
            "pageSize": max_results,
            "orderBy": "modifiedTime desc",
        },
    )
    resp.raise_for_status()

    files = resp.json().get("files", [])
    return {
        "success": True,
        "message": f"Found {len(files)} file(s)",
        "data": {"files": files},
    }


async def _search_files(
    client: httpx.AsyncClient, headers: dict, params: dict
) -> dict:
    """Search files by query."""
    query = params.get("query")
    if not query:
        return {
            "success": False,
            "message": "query parameter is required for search_files",
            "data": {},
        }

    max_results = params.get("max_results", 50)

    resp = await client.get(
        f"{BASE_URL}/files",
        headers=headers,
        params={
            "q": f"{query} and trashed = false",
            "fields": f"files({FILE_FIELDS})",
            "pageSize": max_results,
        },
    )
    resp.raise_for_status()

    files = resp.json().get("files", [])
    return {
        "success": True,
        "message": f"Found {len(files)} file(s) matching query",
        "data": {"files": files},
    }


async def _get_metadata(
    client: httpx.AsyncClient, headers: dict, params: dict
) -> dict:
    """Get file metadata."""
    file_id = params.get("file_id")
    if not file_id:
        return {
            "success": False,
            "message": "file_id is required for get_metadata",
            "data": {},
        }

    resp = await client.get(
        f"{BASE_URL}/files/{file_id}",
        headers=headers,
        params={"fields": "*"},
    )
    resp.raise_for_status()

    return {
        "success": True,
        "message": f"Metadata for file {file_id}",
        "data": resp.json(),
    }


async def _create_folder(
    client: httpx.AsyncClient, headers: dict, params: dict
) -> dict:
    """Create a new folder."""
    folder_name = params.get("file_name")
    if not folder_name:
        return {
            "success": False,
            "message": "file_name is required for create_folder",
            "data": {},
        }

    parent_id = params.get("folder_id", "root")

    resp = await client.post(
        f"{BASE_URL}/files",
        headers=headers,
        json={
            "name": folder_name,
            "mimeType": "application/vnd.google-apps.folder",
            "parents": [parent_id],
        },
    )
    resp.raise_for_status()

    folder = resp.json()
    return {
        "success": True,
        "message": f"Created folder '{folder_name}'",
        "data": {"id": folder["id"], "name": folder.get("name", "")},
    }


async def _upload_file(
    client: httpx.AsyncClient, headers: dict, params: dict
) -> dict:
    """Upload a file via multipart upload (max 5MB)."""
    file_name = params.get("file_name")
    file_content = params.get("file_content")
    if not file_name or not file_content:
        return {
            "success": False,
            "message": "file_name and file_content are required for upload_file",
            "data": {},
        }

    mime_type = params.get("mime_type", "text/plain")
    parent_id = params.get("folder_id", "root")

    # Try base64 decode; if it fails, treat as plain text
    try:
        content_bytes = base64.b64decode(file_content, validate=True)
    except Exception:
        content_bytes = file_content.encode("utf-8")

    metadata = json.dumps({"name": file_name, "parents": [parent_id]})
    boundary = "fliiq_upload_boundary"
    body = (
        f"--{boundary}\r\n"
        f"Content-Type: application/json; charset=UTF-8\r\n\r\n"
        f"{metadata}\r\n"
        f"--{boundary}\r\n"
        f"Content-Type: {mime_type}\r\n\r\n"
    ).encode("utf-8") + content_bytes + f"\r\n--{boundary}--".encode("utf-8")

    upload_headers = {
        "Authorization": headers["Authorization"],
        "Content-Type": f"multipart/related; boundary={boundary}",
    }

    resp = await client.post(
        f"{UPLOAD_URL}/files?uploadType=multipart",
        headers=upload_headers,
        content=body,
    )
    resp.raise_for_status()

    uploaded = resp.json()
    return {
        "success": True,
        "message": f"Uploaded '{file_name}'",
        "data": {"id": uploaded["id"], "name": uploaded.get("name", "")},
    }


async def _export_file(
    client: httpx.AsyncClient, headers: dict, params: dict
) -> dict:
    """Export a Google Workspace file to a different format."""
    file_id = params.get("file_id")
    mime_type = params.get("mime_type")
    if not file_id or not mime_type:
        return {
            "success": False,
            "message": "file_id and mime_type are required for export_file",
            "data": {},
        }

    resp = await client.get(
        f"{BASE_URL}/files/{file_id}/export",
        headers=headers,
        params={"mimeType": mime_type},
    )
    resp.raise_for_status()

    # Text-based exports return text; binary exports get base64-encoded
    content_type = resp.headers.get("content-type", "")
    if "text" in content_type or "json" in content_type or "csv" in content_type:
        export_content = resp.text
    else:
        export_content = base64.b64encode(resp.content).decode("ascii")

    return {
        "success": True,
        "message": f"Exported file {file_id} as {mime_type}",
        "data": {"content": export_content, "mime_type": mime_type},
    }


async def _delete_file(
    client: httpx.AsyncClient, headers: dict, params: dict
) -> dict:
    """Soft-delete a file (move to trash)."""
    file_id = params.get("file_id")
    if not file_id:
        return {
            "success": False,
            "message": "file_id is required for delete_file",
            "data": {},
        }

    resp = await client.patch(
        f"{BASE_URL}/files/{file_id}",
        headers=headers,
        json={"trashed": True},
    )
    resp.raise_for_status()

    return {
        "success": True,
        "message": f"Moved file {file_id} to trash",
        "data": {"trashed_file_id": file_id},
    }
