"""ConnectorPlugin ABC per GCAP-SPEC-CONNECTOR-DESCRIPTOR-0001 section 4."""
from __future__ import annotations

import hashlib
import json
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any

# Fix C-6: capability constants for operation-level enforcement
CAP_READ = 0x1
CAP_PROPOSE = 0x2
CAP_MUTATE = 0x4
CAP_ADMIN = 0x8


@dataclass
class ConnectorContext:
    chronicle_session_id: str = ""
    gsap_context_id: str = ""
    credentials: dict[str, Any] = field(default_factory=dict)
    pipeline_run_id: str = ""
    dag_id: str = ""
    # Fix C-6: capability_mask from the AC, enforced by ConnectorRuntime
    capability_mask: int = 0
    principal_did: str = ""


@dataclass
class ConnectorResult:
    success: bool = False
    data: Any = None
    error: str | None = None
    lineage_cid: str = ""
    metadata: dict[str, Any] = field(default_factory=dict)


class ConnectorPlugin(ABC):
    """Abstract base for governed connectors."""

    connector_id: str = ""
    corpus_entry_cid: str = ""
    capability_mask: int = 0
    declared_endpoints: list[str] = []
    accord_template: str = ""
    gsap_required: bool = True
    chronicle_enabled: bool = True
    # Fix C-6: per-operation capability requirements
    operation_capabilities: dict[str, int] = {}

    def capability_for_operation(self, operation: str) -> int:
        """Return the capability mask required for an operation.
        Defaults to CAP_READ if not explicitly mapped."""
        return self.operation_capabilities.get(operation, CAP_READ)

    @abstractmethod
    async def invoke(
        self, operation: str, parameters: dict[str, Any], context: ConnectorContext
    ) -> ConnectorResult:
        ...

    @abstractmethod
    def health_check(self) -> bool:
        ...

    def compute_parameters_cid(self, parameters: dict[str, Any]) -> str:
        canonical = json.dumps(parameters, sort_keys=True, separators=(",", ":"))
        return "sha256:" + hashlib.sha256(canonical.encode()).hexdigest()

    def descriptor(self) -> dict[str, Any]:
        return {
            "@context": "https://schema.gsap.dev/connector/v1",
            "@type": "ConnectorDescriptor",
            "connector_id": self.connector_id,
            "corpus_entry_cid": self.corpus_entry_cid,
            "capability_mask": self.capability_mask,
            "declared_endpoints": self.declared_endpoints,
            "accord_template": self.accord_template,
            "gsap_required": self.gsap_required,
            "chronicle_enabled": self.chronicle_enabled,
        }
