"""
Z-Arch Extension Context Interface
-----------------------------------------------
Defines the stable `ZArchContext` contract passed to extension lifecycle hooks.

This interface is the supported extension API surface for:
  - project metadata and repository context
  - lifecycle event metadata access
  - logging, prompts, and local command execution
  - configuration read/write helpers
  - cloud, GitHub, and Cloudflare helper operations

Extensions should rely on this facade instead of internal Z-Arch modules so
core implementation details can evolve without breaking extension compatibility.

Copyright © 2026 RAM Cloud Code LLC
Licensed under the Apache License, Version 2.0.
"""

# zarch/extensions/context.py
from __future__ import annotations
from pathlib import Path
from copy import deepcopy
from typing import Any, Dict, Callable, List, Tuple, Optional


class ZArchContext:
    """
    Provides a stable interface to Z Arch internal functionality for extensions.

    This class acts as a facade over internal helper functions used for
    deployment, infrastructure provisioning, file management, IAM configuration,
    and gateway operations.

    Extensions interact exclusively through this class. The underlying
    implementation details are internal to Z Arch and may evolve independently
    without breaking plugin compatibility.
    """

    def __init__(
        self,
        id: str,
        region: str,
        project_root_path: Path,
        cloud: Any | None = None,
        non_interactive: bool = False,
        config: Any | None = None,
        prompter: Any | None = None,
    ) -> None:
        self.id = id
        self.region = region
        self.project_root_path = project_root_path
        self.config = config
        self.non_interactive = non_interactive
        self.prompter = prompter
        self.cloud = cloud
        self._event_data: Dict[str, Any] | None = None

    def get_event_data(self) -> Dict[str, Any] | None:
        """
        Return lifecycle metadata for the currently executing hook, if any.

        This value is optional and may be None for flows that do not provide
        event metadata. Extensions should treat this as best-effort context.
        """
        if self._event_data is None:
            return None
        return deepcopy(self._event_data)

    def _set_event_data(self, event_data: Dict[str, Any] | None) -> None:
        """
        Internal helper used by Z-Arch core to set per-dispatch metadata.

        Extension code should treat this as internal and read metadata via
        get_event_data().
        """
        if event_data is None:
            self._event_data = None
            return
        self._event_data = deepcopy(event_data)

    # Logging
    # ----------------------------------------------------------

    def log(self, message: str, level: Optional[str] = None) -> None:
        raise NotImplementedError

    # Command execution
    # ----------------------------------------------------------

    def run_command(self, command_parts: List[str]) -> Tuple[str, int]:
        raise NotImplementedError

    def gcloud(self, command_parts: List[str]) -> Tuple[str, int]:
        raise NotImplementedError

    # Config
    # ----------------------------------------------------------

    def config_get(self, key: str, default: Any = None) -> Any:
        raise NotImplementedError

    def config_set(self, key: str, value: Any) -> None:
        raise NotImplementedError

    def config_save(self) -> None:
        raise NotImplementedError

    # Prompts
    # ----------------------------------------------------------

    def ask(self, message: str, default: str | None = None,
            required: bool = True, validate: Callable | None = None) -> str:
        raise NotImplementedError

    def choice(self, message: str, choices: list[str],
               default: str | None = None, sub_prompt: str = '') -> str:
        raise NotImplementedError

    def multichoice(self, message: str, choices: list[str],
                    default: list[str] | None = None,
                    sub_prompt: str = "(space to toggle, enter to confirm)") -> List[str]:
        raise NotImplementedError

    def yes_no(self, message: str, default: bool = True,
               sub_prompt: str = '') -> bool:
        raise NotImplementedError

    def review_and_confirm(self):
        raise NotImplementedError

    # GCP Helpers
    # ----------------------------------------------------------

    def ensure_service_account(self, service_account_name: str, display_name: str) -> str:
        raise NotImplementedError

    def secret_exists(self, secret_name: str) -> bool:
        raise NotImplementedError

    def store_secret(self, secret_name: str, secret_value: str) -> None:
        raise NotImplementedError

    def get_secret(self, secret_name: str) -> str:
        raise NotImplementedError

    def get_service_url(self, service_name: str) -> str:
        raise NotImplementedError

    def get_env_var(self, service_name: str, env_var_key: str) -> str:
        raise NotImplementedError

    def set_env_vars(self, service_name: str, env_vars: Dict[str, str]) -> None:
        raise NotImplementedError

    # Github
    # ----------------------------------------------------------

    def github(self):
        raise NotImplementedError

    def get_connected_repo(self) -> tuple[str, str]:
        raise NotImplementedError

    # Cloudflare
    # ----------------------------------------------------------

    def update_edge_proxy(self, project_name: str | None = None):
        raise NotImplementedError

    def set_edge_proxy_envs(self, env_vars: Dict[str, str],
                            project_name: str | None = None):
        raise NotImplementedError

    def deploy_cf_worker(self,
        script_name: str,
        repo_root_dir: str,
        repo_full: str | None = None,
        branch: str | None = None,
        domain: str | None = None,
    ):
        raise NotImplementedError

    def set_worker_route(self, script_name: str, domain: str,
                         route: str = "/api/*"):
        raise NotImplementedError

    def deploy_cf_pages(self, domain: str,
                        project_name: str | None = None,
                        repo_full: str | None = None,
                        branch: str | None = None):
        raise NotImplementedError
