from __future__ import annotations

import base64
from functools import lru_cache
from pathlib import Path

import httpx
from google.auth.transport.requests import Request
from google.oauth2 import service_account

from app.core.config import get_settings


GOOGLE_DOCUMENT_AI_SCOPE = "https://www.googleapis.com/auth/cloud-platform"


def is_google_document_ai_configured() -> bool:
    settings = get_settings()
    service_account_file = (settings.google_document_ai_service_account_file or "").strip()
    return bool(
        settings.google_document_ai_project_id
        and settings.google_document_ai_ocr_processor_id
        and service_account_file
        and Path(service_account_file).exists()
    )


@lru_cache(maxsize=1)
def _load_document_ai_credentials(service_account_file: str) -> service_account.Credentials:
    return service_account.Credentials.from_service_account_file(
        service_account_file,
        scopes=[GOOGLE_DOCUMENT_AI_SCOPE],
    )


def _get_document_ai_access_token() -> str:
    settings = get_settings()
    service_account_file = (settings.google_document_ai_service_account_file or "").strip()
    if not service_account_file:
        raise RuntimeError("Document AI non configurato: service account mancante.")
    credentials = _load_document_ai_credentials(service_account_file)
    if not credentials.valid or credentials.expired or not credentials.token:
        credentials.refresh(Request())
    if not credentials.token:
        raise RuntimeError("Document AI non ha restituito un access token valido.")
    return credentials.token


def _document_ai_process_endpoint(*, project_id: str, location: str, processor_id: str) -> str:
    normalized_location = (location or "eu").strip().lower()
    host = "https://documentai.googleapis.com/v1"
    if normalized_location and normalized_location != "us":
        host = f"https://{normalized_location}-documentai.googleapis.com/v1"
    return (
        f"{host}/projects/{project_id}/locations/{normalized_location}/processors/{processor_id}:process"
    )


def process_document_with_document_ai(
    *,
    raw_bytes: bytes,
    mime_type: str,
    processor_id: str | None = None,
) -> dict[str, object] | None:
    if not raw_bytes or not is_google_document_ai_configured():
        return None

    settings = get_settings()
    project_id = (settings.google_document_ai_project_id or "").strip()
    location = (settings.google_document_ai_location or "eu").strip().lower() or "eu"
    selected_processor_id = (processor_id or settings.google_document_ai_ocr_processor_id or "").strip()
    if not project_id or not selected_processor_id:
        return None

    access_token = _get_document_ai_access_token()
    endpoint = _document_ai_process_endpoint(
        project_id=project_id,
        location=location,
        processor_id=selected_processor_id,
    )
    payload = {
        "skipHumanReview": True,
        "rawDocument": {
            "mimeType": mime_type,
            "content": base64.b64encode(raw_bytes).decode("ascii"),
        },
    }

    with httpx.Client(timeout=settings.google_document_ai_request_timeout_seconds) as client:
        response = client.post(
            endpoint,
            headers={
                "Authorization": f"Bearer {access_token}",
                "Content-Type": "application/json",
            },
            json=payload,
        )
        response.raise_for_status()
        parsed = response.json()

    document = parsed.get("document") if isinstance(parsed, dict) else {}
    text = str(document.get("text") or "").strip() if isinstance(document, dict) else ""
    if not text:
        return None
    return {
        "text": text,
        "document": document if isinstance(document, dict) else {},
        "processor_id": selected_processor_id,
        "location": location,
    }
