"""GCP cloud resource state reader.

Reads live state of GCP resources using the Google Cloud SDK.
Falls back to gcloud CLI when SDK is unavailable.
"""

from __future__ import annotations

import json
import logging
import os
import subprocess
from dataclasses import dataclass, field
from typing import Any, Optional

logger = logging.getLogger(__name__)


@dataclass
class GCPResourceState:
    """Live state of a GCP resource."""
    self_link: str
    resource_id: str
    resource_type: str
    project: str
    zone: Optional[str] = None
    region: Optional[str] = None
    name: str = ""
    labels: dict[str, str] = field(default_factory=dict)
    properties: dict[str, Any] = field(default_factory=dict)
    exists: bool = True


class GCPProvider:
    """Read live GCP resource state.

    Authentication uses standard GCP credential chain:
      - GOOGLE_APPLICATION_CREDENTIALS
      - gcloud auth application-default
    """

    def __init__(self, project: Optional[str] = None) -> None:
        self.project = project or os.environ.get("GOOGLE_CLOUD_PROJECT", os.environ.get("GCP_PROJECT", ""))
        self._sdk_available = False
        self._try_init_sdk()

    def _try_init_sdk(self) -> None:
        """Attempt to initialize Google Cloud SDK."""
        try:
            from google.cloud import compute_v1
            self._sdk_available = True
            logger.info("GCP SDK initialized successfully")
        except ImportError:
            logger.info("Google Cloud SDK not installed, will use CLI fallback")
        except Exception as e:
            logger.warning("GCP SDK init failed: %s", e)

    def get_compute_instance(self, instance_name: str, zone: str) -> GCPResourceState:
        """Get the live state of a Compute Engine instance."""
        if self._sdk_available:
            try:
                from google.cloud import compute_v1
                client = compute_v1.InstancesClient()
                instance = client.get(project=self.project, zone=zone, instance=instance_name)
                return GCPResourceState(
                    self_link=instance.self_link,
                    resource_id=str(instance.id),
                    resource_type="google_compute_instance",
                    project=self.project,
                    zone=zone,
                    name=instance.name,
                    labels=dict(instance.labels) if instance.labels else {},
                    properties={
                        "machine_type": instance.machine_type.split("/")[-1] if instance.machine_type else "",
                        "status": instance.status,
                        "can_ip_forward": instance.can_ip_forward,
                        "deletion_protection": instance.deletion_protection,
                        "network_interfaces": [
                            {
                                "network": ni.network,
                                "subnetwork": ni.subnetwork,
                                "access_configs": [
                                    {"type": ac.type_, "nat_ip": ac.nat_i_p}
                                    for ac in (ni.access_configs or [])
                                ],
                            }
                            for ni in (instance.network_interfaces or [])
                        ],
                        "service_accounts": [
                            {"email": sa.email, "scopes": list(sa.scopes or [])}
                            for sa in (instance.service_accounts or [])
                        ],
                        "shielded_instance_config": {
                            "enable_secure_boot": instance.shielded_instance_config.enable_secure_boot
                            if instance.shielded_instance_config else False,
                        },
                    },
                    exists=True,
                )
            except Exception as e:
                if "404" in str(e) or "notFound" in str(e):
                    return GCPResourceState(
                        self_link="", resource_id=instance_name,
                        resource_type="google_compute_instance",
                        project=self.project, zone=zone, exists=False,
                    )
                logger.warning("SDK get_compute_instance failed: %s", e)

        return self._get_via_cli("compute", "instances", instance_name, zone=zone)

    def get_storage_bucket(self, bucket_name: str) -> GCPResourceState:
        """Get the live state of a Cloud Storage bucket."""
        if self._sdk_available:
            try:
                from google.cloud import storage
                client = storage.Client(project=self.project)
                bucket = client.get_bucket(bucket_name)
                return GCPResourceState(
                    self_link=bucket.self_link or "",
                    resource_id=bucket_name,
                    resource_type="google_storage_bucket",
                    project=self.project,
                    name=bucket_name,
                    labels=dict(bucket.labels) if bucket.labels else {},
                    properties={
                        "location": bucket.location,
                        "storage_class": bucket.storage_class,
                        "versioning_enabled": bucket.versioning_enabled,
                        "uniform_bucket_level_access": bucket.iam_configuration.get(
                            "uniformBucketLevelAccess", {}).get("enabled", False)
                        if bucket.iam_configuration else False,
                        "public_access_prevention": bucket.iam_configuration.get(
                            "publicAccessPrevention", "unspecified")
                        if bucket.iam_configuration else "unspecified",
                        "logging": bucket.logging is not None,
                    },
                    exists=True,
                )
            except Exception as e:
                if "404" in str(e) or "NotFound" in str(e):
                    return GCPResourceState(
                        self_link="", resource_id=bucket_name,
                        resource_type="google_storage_bucket",
                        project=self.project, exists=False,
                    )
                logger.warning("SDK get_storage_bucket failed: %s", e)

        return self._get_via_cli("storage", "buckets", bucket_name)

    def get_firewall_rule(self, firewall_name: str) -> GCPResourceState:
        """Get the live state of a VPC firewall rule."""
        if self._sdk_available:
            try:
                from google.cloud import compute_v1
                client = compute_v1.FirewallsClient()
                fw = client.get(project=self.project, firewall=firewall_name)
                return GCPResourceState(
                    self_link=fw.self_link,
                    resource_id=str(fw.id),
                    resource_type="google_compute_firewall",
                    project=self.project,
                    name=fw.name,
                    properties={
                        "network": fw.network,
                        "direction": fw.direction,
                        "priority": fw.priority,
                        "source_ranges": list(fw.source_ranges or []),
                        "destination_ranges": list(fw.destination_ranges or []),
                        "allowed": [
                            {"protocol": a.I_p_protocol, "ports": list(a.ports or [])}
                            for a in (fw.allowed or [])
                        ],
                        "denied": [
                            {"protocol": d.I_p_protocol, "ports": list(d.ports or [])}
                            for d in (fw.denied or [])
                        ],
                        "disabled": fw.disabled,
                        "target_tags": list(fw.target_tags or []),
                        "source_tags": list(fw.source_tags or []),
                    },
                    exists=True,
                )
            except Exception as e:
                if "404" in str(e) or "notFound" in str(e):
                    return GCPResourceState(
                        self_link="", resource_id=firewall_name,
                        resource_type="google_compute_firewall",
                        project=self.project, exists=False,
                    )
                logger.warning("SDK get_firewall_rule failed: %s", e)

        return self._get_via_cli("compute", "firewall-rules", firewall_name)

    def _get_via_cli(
        self,
        service: str,
        resource_type: str,
        resource_name: str,
        zone: Optional[str] = None,
    ) -> GCPResourceState:
        """Fallback to gcloud CLI."""
        try:
            cmd = ["gcloud", service, resource_type, "describe", resource_name,
                   "--project", self.project, "--format", "json"]
            if zone:
                cmd.extend(["--zone", zone])

            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            if result.returncode != 0:
                return GCPResourceState(
                    self_link="", resource_id=resource_name,
                    resource_type=f"google_{service}_{resource_type}".replace("-", "_"),
                    project=self.project, zone=zone, exists=False,
                )
            data = json.loads(result.stdout)
            return GCPResourceState(
                self_link=data.get("selfLink", ""),
                resource_id=data.get("id", resource_name),
                resource_type=f"google_{service}_{resource_type}".replace("-", "_"),
                project=self.project,
                zone=zone,
                name=data.get("name", resource_name),
                labels=data.get("labels", {}),
                properties=data,
                exists=True,
            )
        except Exception as e:
            logger.warning("gcloud CLI fallback failed: %s", e)
            return GCPResourceState(
                self_link="", resource_id=resource_name,
                resource_type=f"google_{service}_{resource_type}",
                project=self.project, zone=zone, exists=False,
            )

    def flatten_to_attributes(self, state: GCPResourceState) -> dict[str, Any]:
        """Flatten GCPResourceState to attribute dict for comparison."""
        attrs: dict[str, Any] = {
            "name": state.name,
            "project": state.project,
        }
        if state.zone:
            attrs["zone"] = state.zone
        if state.region:
            attrs["region"] = state.region
        if state.labels:
            for k, v in state.labels.items():
                attrs[f"labels.{k}"] = v
        for k, v in state.properties.items():
            if isinstance(v, (str, int, float, bool)):
                attrs[k] = v
            elif isinstance(v, list):
                attrs[k] = v
        return attrs
