"""Remote state backends — fetch Terraform state from cloud storage.

Supports GCS, S3, Azure Blob Storage, and Terraform Cloud.
Each backend authenticates via standard cloud credentials (ADC, AWS
creds, Azure DefaultAzureCredential) or explicit token.
"""

from __future__ import annotations

import logging
import os

_log = logging.getLogger(__name__)


async def fetch_remote_state(
    uri: str,
    credentials: str | None = None,
) -> bytes:
    """Dispatch to the appropriate backend based on URI scheme.

    Returns raw state JSON bytes.
    Raises RemoteState*Error on failures.
    """
    from complyform.core.errors import RemoteStateUnsupportedError

    if uri.startswith("gs://"):
        bucket, path = _parse_gs_uri(uri)
        return await fetch_gcs_state(bucket, path, credentials)

    if uri.startswith("s3://"):
        bucket, path = _parse_s3_uri(uri)
        return await fetch_s3_state(bucket, path)

    if uri.startswith("azure://"):
        account, container, path = _parse_azure_uri(uri)
        return await fetch_azure_state(account, container, path)

    if "app.terraform.io" in uri:
        org, workspace = _parse_tfc_uri(uri)
        return await fetch_tfc_state(org, workspace)

    scheme = uri.split("://")[0] if "://" in uri else uri.split("/")[0]
    raise RemoteStateUnsupportedError(scheme)


def _parse_gs_uri(uri: str) -> tuple[str, str]:
    """Parse gs://bucket/path → (bucket, path)."""
    stripped = uri[len("gs://") :]
    parts = stripped.split("/", 1)
    bucket = parts[0]
    path = parts[1] if len(parts) > 1 else ""
    return bucket, path


def _parse_s3_uri(uri: str) -> tuple[str, str]:
    """Parse s3://bucket/path → (bucket, path)."""
    stripped = uri[len("s3://") :]
    parts = stripped.split("/", 1)
    bucket = parts[0]
    path = parts[1] if len(parts) > 1 else ""
    return bucket, path


def _parse_azure_uri(uri: str) -> tuple[str, str, str]:
    """Parse azure://account/container/path → (account, container, path)."""
    stripped = uri[len("azure://") :]
    parts = stripped.split("/", 2)
    if len(parts) < 3:
        from complyform.core.errors import RemoteStateNotFoundError

        raise RemoteStateNotFoundError(uri)
    return parts[0], parts[1], parts[2]


def _parse_tfc_uri(uri: str) -> tuple[str, str]:
    """Parse app.terraform.io/org/workspace → (org, workspace)."""
    # Strip protocol if present
    cleaned = uri.replace("https://", "").replace("http://", "")
    # Remove app.terraform.io/ prefix
    cleaned = cleaned.replace("app.terraform.io/", "")
    parts = cleaned.split("/", 1)
    if len(parts) < 2:
        from complyform.core.errors import RemoteStateNotFoundError

        raise RemoteStateNotFoundError(uri)
    return parts[0], parts[1]


async def fetch_gcs_state(
    bucket: str,
    path: str,
    credentials: str | None = None,
) -> bytes:
    """Fetch state from Google Cloud Storage."""
    from complyform.core.errors import (
        RemoteStateAuthError,
        RemoteStateNotFoundError,
    )

    try:
        from google.cloud import storage  # type: ignore

        if credentials:
            client = storage.Client.from_service_account_json(credentials)
        else:
            client = storage.Client()

        bucket_obj = client.bucket(bucket)
        blob = bucket_obj.blob(path)
        return blob.download_as_bytes()  # type: ignore[no-any-return]

    except Exception as exc:
        exc_str = str(exc).lower()
        if "403" in exc_str or "credential" in exc_str:
            raise RemoteStateAuthError("GCS", str(exc)) from exc
        if "404" in exc_str or "not found" in exc_str:
            raise RemoteStateNotFoundError(f"gs://{bucket}/{path}") from exc
        raise RemoteStateAuthError("GCS", str(exc)) from exc


async def fetch_s3_state(bucket: str, path: str) -> bytes:
    """Fetch state from AWS S3."""
    from complyform.core.errors import (
        RemoteStateAuthError,
        RemoteStateNotFoundError,
    )

    try:
        import boto3  # type: ignore
        from botocore.exceptions import ClientError  # type: ignore

        client = boto3.client("s3")
        response = client.get_object(Bucket=bucket, Key=path)
        return response["Body"].read()  # type: ignore[no-any-return]

    except ClientError as exc:
        code = exc.response.get("Error", {}).get("Code", "")
        if code in ("NoSuchKey", "NoSuchBucket", "404"):
            raise RemoteStateNotFoundError(f"s3://{bucket}/{path}") from exc
        if code in ("AccessDenied", "403"):
            raise RemoteStateAuthError("S3", str(exc)) from exc
        raise RemoteStateAuthError("S3", str(exc)) from exc
    except ImportError as exc:
        raise RemoteStateAuthError(
            "S3",
            "boto3 not installed. Install with: pip install complyform[s3]",
        ) from exc
    except Exception as exc:
        raise RemoteStateAuthError("S3", str(exc)) from exc


async def fetch_azure_state(
    account: str,
    container: str,
    path: str,
) -> bytes:
    """Fetch state from Azure Blob Storage."""
    from complyform.core.errors import (
        RemoteStateAuthError,
        RemoteStateNotFoundError,
    )

    try:
        from azure.identity import (  # type: ignore
            DefaultAzureCredential,
        )
        from azure.storage.blob import (  # type: ignore
            BlobServiceClient,
        )

        credential = DefaultAzureCredential()
        blob_service = BlobServiceClient(
            account_url=f"https://{account}.blob.core.windows.net",
            credential=credential,
        )
        container_client = blob_service.get_container_client(container)
        blob_data = container_client.download_blob(path)
        return blob_data.readall()  # type: ignore[no-any-return]

    except ImportError as exc:
        raise RemoteStateAuthError(
            "Azure",
            "azure-storage-blob not installed."
            " Install with: pip install complyform[azure]",
        ) from exc
    except Exception as exc:
        exc_str = str(exc).lower()
        if "not found" in exc_str or "404" in exc_str:
            raise RemoteStateNotFoundError(
                f"azure://{account}/{container}/{path}"
            ) from exc
        raise RemoteStateAuthError("Azure", str(exc)) from exc


async def fetch_tfc_state(org: str, workspace: str) -> bytes:
    """Fetch current state from Terraform Cloud."""
    from complyform.core.errors import (
        RemoteStateAuthError,
        RemoteStateNetworkError,
        RemoteStateNotFoundError,
    )

    token = os.environ.get("TF_TOKEN", "")
    if not token:
        raise RemoteStateAuthError(
            "Terraform Cloud",
            "TF_TOKEN environment variable not set",
        )

    import httpx

    base_url = "https://app.terraform.io/api/v2"

    try:
        async with httpx.AsyncClient() as client:
            # Get workspace ID
            ws_resp = await client.get(
                f"{base_url}/organizations/{org}/workspaces/{workspace}",
                headers={
                    "Authorization": f"Bearer {token}",
                    "Content-Type": "application/vnd.api+json",
                },
            )

            if ws_resp.status_code == 404:
                raise RemoteStateNotFoundError(f"app.terraform.io/{org}/{workspace}")
            if ws_resp.status_code in (401, 403):
                raise RemoteStateAuthError(
                    "Terraform Cloud",
                    f"Authentication failed (HTTP {ws_resp.status_code})",
                )
            ws_resp.raise_for_status()

            ws_data = ws_resp.json()
            ws_id = ws_data["data"]["id"]

            # Get current state version
            sv_resp = await client.get(
                f"{base_url}/workspaces/{ws_id}/current-state-version",
                headers={
                    "Authorization": f"Bearer {token}",
                    "Content-Type": "application/vnd.api+json",
                },
            )

            if sv_resp.status_code == 404:
                raise RemoteStateNotFoundError(f"app.terraform.io/{org}/{workspace}")
            sv_resp.raise_for_status()

            sv_data = sv_resp.json()
            download_url = sv_data["data"]["attributes"]["hosted-state-download-url"]

            # Download state
            state_resp = await client.get(
                download_url,
                headers={"Authorization": f"Bearer {token}"},
            )
            state_resp.raise_for_status()
            return state_resp.content

    except (
        RemoteStateNotFoundError,
        RemoteStateAuthError,
    ):
        raise
    except httpx.HTTPStatusError as exc:
        raise RemoteStateNetworkError(
            "Terraform Cloud",
            f"HTTP {exc.response.status_code}",
        ) from exc
    except httpx.RequestError as exc:
        raise RemoteStateNetworkError(
            "Terraform Cloud",
            str(exc),
        ) from exc
