"""
Google Cloud Storage source connector.

Auth (env vars):
    GOOGLE_APPLICATION_CREDENTIALS   (path to service account JSON)
    (On GKE/Cloud Run: Workload Identity — no env var needed)

URI format:
    gcs://bucket/prefix/
    gs://bucket/prefix/   (alias)
"""

from __future__ import annotations

import contextlib
import fnmatch
import tempfile
from collections.abc import Iterator
from pathlib import Path
from urllib.parse import urlparse

from .base import SourceFile
from .registry import register_source


class GCSSource:
    scheme = "gcs"

    def _get_client(self):
        try:
            from google.cloud import storage
        except ImportError as e:
            raise ImportError(
                "google-cloud-storage not installed. Run: pip install 'coresdk-extractor[gcs]'"
            ) from e
        return storage.Client()

    def list(self, uri: str, glob_pattern: str | None = None) -> Iterator[SourceFile]:
        parsed = urlparse(uri)
        bucket_name = parsed.netloc
        prefix = parsed.path.lstrip("/")
        client = self._get_client()
        bucket = client.bucket(bucket_name)
        for blob in client.list_blobs(bucket, prefix=prefix):
            filename = blob.name.split("/")[-1]
            if not filename:
                continue
            if glob_pattern and not fnmatch.fnmatch(filename, glob_pattern):
                continue
            yield SourceFile(
                uri=f"gcs://{bucket_name}/{blob.name}",
                filename=filename,
                size_bytes=blob.size,
                etag=blob.etag,
                version_id=str(blob.generation),
                last_modified=blob.updated.isoformat() if blob.updated else None,
                content_type=blob.content_type,
            )

    @contextlib.contextmanager
    def fetch(self, source_file: SourceFile, tmp_dir: Path | None = None) -> Iterator[Path]:
        parsed = urlparse(source_file.uri)
        bucket_name = parsed.netloc
        blob_name = parsed.path.lstrip("/")
        client = self._get_client()
        suffix = Path(source_file.filename).suffix or ".bin"
        with tempfile.NamedTemporaryFile(suffix=suffix, dir=tmp_dir, delete=False) as tmp:
            tmp_path = Path(tmp.name)
        try:
            bucket = client.bucket(bucket_name)
            blob = bucket.blob(blob_name)
            blob.download_to_filename(str(tmp_path))
            yield tmp_path
        finally:
            with contextlib.suppress(FileNotFoundError):
                tmp_path.unlink()


class GSSource(GCSSource):
    scheme = "gs"


register_source(GCSSource())
register_source(GSSource())
