from __future__ import annotations

import re
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from functools import lru_cache
from pathlib import Path

import firebase_admin
from firebase_admin import credentials, storage

DEFAULT_BUCKET_NAME = "atmiya-db.appspot.com"
DEFAULT_STORAGE_PREFIX = "sdm/svayamsevak-receipts"
SIGNED_URL_TTL = timedelta(days=6, hours=23)

@dataclass
class UploadedFile:
    url: str
    bucket_name: str
    storage_path: str


def _discover_service_account_file() -> Path | None:
    current_dir = Path(__file__).resolve().parent
    project_root = current_dir.parent.parent
    candidate_patterns = (
        "*firebase*adminsdk*.json",
        "*firebase*.json",
        "*adminsdk*.json",
    )

    search_roots = [
        current_dir,
        project_root / "config",
        project_root / "app" / "services",
    ]

    for search_root in search_roots:
        if not search_root.exists():
            continue
        for pattern in candidate_patterns:
            matches = sorted(search_root.glob(pattern))
            if matches:
                return matches[0]

    return None


@lru_cache(maxsize=1)
def get_bucket():
    if firebase_admin._apps:
        return storage.bucket()

    discovered_service_account_file = _discover_service_account_file()

    if discovered_service_account_file and discovered_service_account_file.exists():
        credential = credentials.Certificate(str(discovered_service_account_file))
        app = firebase_admin.initialize_app(
            credential,
            {"storageBucket": DEFAULT_BUCKET_NAME},
        )
        return storage.bucket(app=app)

    google_application_credentials = Path(str(Path.cwd() / "missing"))
    if "GOOGLE_APPLICATION_CREDENTIALS" in __import__("os").environ:
        google_application_credentials = Path(__import__("os").environ["GOOGLE_APPLICATION_CREDENTIALS"])

    if google_application_credentials.exists():
        app = firebase_admin.initialize_app(options={"storageBucket": DEFAULT_BUCKET_NAME})
        return storage.bucket(app=app)

    raise RuntimeError("Firebase service-account JSON file not found for the receipt service.")


def safe_segment(value: str) -> str:
    return re.sub(r"[^a-zA-Z0-9_-]+", "-", value).strip("-").lower() or "receipt"


def build_storage_path(receipt_number: str) -> str:
    timestamp = datetime.now(timezone.utc)
    date_segment = timestamp.strftime("%Y%m%d")
    return f"{DEFAULT_STORAGE_PREFIX}/{date_segment}/{safe_segment(receipt_number)}.pdf"


def upload_pdf_bytes(pdf_bytes: bytes, receipt_number: str) -> UploadedFile:
    bucket = get_bucket()
    storage_path = build_storage_path(receipt_number)
    blob = bucket.blob(storage_path)

    try:
        blob.upload_from_string(pdf_bytes, content_type="application/pdf")
        signed_url = blob.generate_signed_url(
            version="v4",
            expiration=datetime.now(timezone.utc) + SIGNED_URL_TTL,
            method="GET",
        )
    except Exception as exc:
        message = str(exc)
        likely_clock_skew = "invalid_grant" in message and "reasonable timeframe" in message
        if likely_clock_skew:
            raise RuntimeError(
                "Firebase upload auth failed (invalid_grant). Check system clock/timezone and rotate the Firebase service-account key if needed."
            ) from exc
        raise RuntimeError(f"Firebase upload failed: {message}") from exc

    return UploadedFile(url=signed_url, bucket_name=bucket.name, storage_path=storage_path)
