"""
In-memory state store for all emulated GCP resources.

Provides a thread-safe, hierarchical store keyed by:
    (service, project, resource_type, resource_id)

Supports listing, CRUD, and filtered queries.
"""

import copy
import threading
import time
import uuid
from typing import Any, Dict, List, Optional


class StateStore:
    """Thread-safe in-memory store for emulated GCP resources."""

    def __init__(self):
        self._lock = threading.RLock()
        self._resources: Dict[str, Dict[str, Any]] = {}
        self._operations: Dict[str, Dict[str, Any]] = {}

    def _make_key(self, service: str, project: str, resource_type: str, resource_id: str) -> str:
        return f"{service}/{project}/{resource_type}/{resource_id}"

    def put(
        self,
        service: str,
        project: str,
        resource_type: str,
        resource_id: str,
        data: Dict[str, Any],
    ) -> Dict[str, Any]:
        key = self._make_key(service, project, resource_type, resource_id)
        with self._lock:
            entry = copy.deepcopy(data)
            entry.setdefault("_meta", {})
            entry["_meta"]["created_at"] = entry["_meta"].get(
                "created_at", time.time()
            )
            entry["_meta"]["updated_at"] = time.time()
            entry["_meta"]["key"] = key
            self._resources[key] = entry
        return self.get(service, project, resource_type, resource_id)

    def get(
        self,
        service: str,
        project: str,
        resource_type: str,
        resource_id: str,
    ) -> Optional[Dict[str, Any]]:
        key = self._make_key(service, project, resource_type, resource_id)
        with self._lock:
            res = self._resources.get(key)
            if res is None:
                return None
            return self._strip_meta(copy.deepcopy(res))

    def delete(
        self,
        service: str,
        project: str,
        resource_type: str,
        resource_id: str,
    ) -> bool:
        key = self._make_key(service, project, resource_type, resource_id)
        with self._lock:
            return self._resources.pop(key, None) is not None

    def list(
        self,
        service: str,
        project: str,
        resource_type: str,
        filter_fn: Optional[callable] = None,
    ) -> List[Dict[str, Any]]:
        prefix = f"{service}/{project}/{resource_type}/"
        with self._lock:
            results = []
            for key, val in self._resources.items():
                if key.startswith(prefix):
                    item = self._strip_meta(copy.deepcopy(val))
                    if filter_fn is None or filter_fn(item):
                        results.append(item)
            return results

    def exists(
        self,
        service: str,
        project: str,
        resource_type: str,
        resource_id: str,
    ) -> bool:
        key = self._make_key(service, project, resource_type, resource_id)
        with self._lock:
            return key in self._resources

    def clear(self, service: Optional[str] = None):
        with self._lock:
            if service is None:
                self._resources.clear()
                self._operations.clear()
            else:
                keys_to_remove = [
                    k for k in self._resources if k.startswith(f"{service}/")
                ]
                for k in keys_to_remove:
                    del self._resources[k]

    def create_operation(
        self,
        service: str,
        project: str,
        zone: Optional[str] = None,
        region: Optional[str] = None,
        target_link: str = "",
        operation_type: str = "insert",
    ) -> Dict[str, Any]:
        op_id = str(uuid.uuid4())[:8]
        op_name = f"operation-{op_id}"

        operation = {
            "kind": f"{service}#operation",
            "id": op_id,
            "name": op_name,
            "status": "DONE",
            "progress": 100,
            "operationType": operation_type,
            "targetLink": target_link,
            "insertTime": time.strftime("%Y-%m-%dT%H:%M:%S.000-00:00", time.gmtime()),
            "startTime": time.strftime("%Y-%m-%dT%H:%M:%S.000-00:00", time.gmtime()),
            "endTime": time.strftime("%Y-%m-%dT%H:%M:%S.000-00:00", time.gmtime()),
        }

        if zone:
            operation["zone"] = zone
        if region:
            operation["region"] = region

        scope = zone or region or "global"
        op_key = f"{service}/{project}/operations/{scope}/{op_name}"
        with self._lock:
            self._operations[op_key] = operation

        return operation

    def get_operation(
        self,
        service: str,
        project: str,
        operation_name: str,
        zone: Optional[str] = None,
        region: Optional[str] = None,
    ) -> Optional[Dict[str, Any]]:
        scope = zone or region or "global"
        op_key = f"{service}/{project}/operations/{scope}/{operation_name}"
        with self._lock:
            return copy.deepcopy(self._operations.get(op_key))

    @staticmethod
    def _strip_meta(data: Dict[str, Any]) -> Dict[str, Any]:
        data.pop("_meta", None)
        return data


state = StateStore()
