"""Cloudflare env var propagation adapter.

Pushes project_env_vars to a CF Pages project as either Worker Secrets
(secret_text) or plain environment variables (plain_text), matching the
visibility flag stored in Core.

CF Pages API reference:
  PATCH /accounts/{account_id}/pages/projects/{project_name}
  Body: { "deployment_configs": { "production": { "env_vars": {...} }, "preview": {...} } }

Secret vars use ``{"type": "secret_text", "value": "..."}``
Public vars use ``{"type": "plain_text",   "value": "..."}``

Replacing the entire env_vars map on each sync is intentional — CF Pages treats
a PATCH as a full replacement of the env_vars key, so stale/deleted keys are
automatically cleared.

Abstraction note: the protocol below keeps the domain service decoupled from CF.
Swap in a different implementation for Amplify, AWS, etc. without touching Core.
"""
from __future__ import annotations

import os
from typing import Any, Protocol, runtime_checkable


@runtime_checkable
class EnvVarAdapter(Protocol):
    """Protocol all env var propagation adapters must satisfy."""

    async def sync_to_hosting(
        self,
        project_ref: str,
        entries: list[dict],
    ) -> None:
        """Push all env var entries to the hosting provider.

        entries: list of {key, value, visibility, environment}
        """
        ...

    async def write_example_file(
        self,
        repo_path: str,
        entries: list[dict],
    ) -> None:
        """Write .env.example to the repo checkout with public vars only."""
        ...


class CloudflareEnvVarAdapter:
    """Sync project_env_vars to a CF Pages project."""

    def __init__(self) -> None:
        from src.domain.hosting.adapters.cloudflare_pages import CloudflarePagesProvider
        self._provider = CloudflarePagesProvider()

    async def sync_to_hosting(
        self,
        project_ref: str,
        entries: list[dict],
    ) -> None:
        """Push all env vars to the CF Pages project (production + preview configs)."""
        from src.domain.hosting.deployment_targets import pages_project_name
        from urllib.parse import quote

        production_vars: dict[str, Any] = {}
        preview_vars: dict[str, Any] = {}

        for e in entries:
            env = e.get("environment", "all")
            var_type = "secret_text" if e.get("visibility") == "secret" else "plain_text"
            var_entry = {"type": var_type, "value": e["value"]}
            if env in ("all", "production"):
                production_vars[e["key"]] = var_entry
            if env in ("all", "preview"):
                preview_vars[e["key"]] = var_entry

        body = {
            "deployment_configs": {
                "production": {"env_vars": production_vars},
                "preview": {"env_vars": preview_vars},
            }
        }
        project_name = pages_project_name(project_ref)
        await self._provider._request(
            "PATCH",
            f"/pages/projects/{quote(project_name, safe='')}",
            json_body=body,
            expected={200},
        )

    async def retry_runtime_deployments(self, project_ref: str) -> list[str]:
        """Rebuild current Pages deployments so newly synced secrets take effect."""
        from src.config import get_settings

        settings = get_settings()
        return await self._provider.retry_latest_branch_deployments(
            project_ref,
            branches=("preview", settings.hosting_preview_branch or "preview", "main"),
        )

    async def write_example_file(
        self,
        repo_path: str,
        entries: list[dict],
    ) -> None:
        """Write .env.example with public vars only. Never writes secrets."""
        public = [e for e in entries if e.get("visibility") == "public"]
        if not public:
            return
        path = os.path.join(repo_path, ".env.example")
        lines = [f'{e["key"]}={e["value"]}\n' for e in public]
        with open(path, "w", encoding="utf-8") as f:
            f.writelines(lines)
