"""Adapter-based connector framework — provider interfaces only (Phase 9.0).

Business services must never contain vendor-specific device logic.
Concrete adapters register by adapter_key and implement these protocols.
"""
from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Protocol, runtime_checkable
from uuid import UUID

from app.models.types import ConnectorCapability


class ConnectorHealth(str, Enum):
    UNKNOWN = "unknown"
    HEALTHY = "healthy"
    DEGRADED = "degraded"
    UNAVAILABLE = "unavailable"


@dataclass(frozen=True)
class ConnectorContext:
    tenant_id: UUID
    sports_center_id: UUID | None = None
    branch_id: UUID | None = None
    device_id: UUID | None = None
    settings: dict[str, Any] = field(default_factory=dict)


@dataclass(frozen=True)
class ConnectorResult:
    success: bool
    code: str
    message: str | None = None
    data: dict[str, Any] = field(default_factory=dict)


@runtime_checkable
class DeviceConnector(Protocol):
    """Base connector for any attendance/access/payment device."""

    capability: ConnectorCapability
    adapter_key: str

    async def connect(self, ctx: ConnectorContext) -> ConnectorResult: ...

    async def disconnect(self, ctx: ConnectorContext) -> ConnectorResult: ...

    async def health(self, ctx: ConnectorContext) -> ConnectorHealth: ...


@runtime_checkable
class QRConnector(DeviceConnector, Protocol):
    async def scan(self, ctx: ConnectorContext, *, payload: str) -> ConnectorResult: ...

    async def issue(self, ctx: ConnectorContext, *, subject_ref: str) -> ConnectorResult: ...


@runtime_checkable
class RFIDConnector(DeviceConnector, Protocol):
    async def read_tag(self, ctx: ConnectorContext) -> ConnectorResult: ...

    async def bind_tag(
        self, ctx: ConnectorContext, *, tag_uid: str, subject_ref: str
    ) -> ConnectorResult: ...


@runtime_checkable
class BarcodeConnector(DeviceConnector, Protocol):
    async def scan(self, ctx: ConnectorContext, *, barcode: str) -> ConnectorResult: ...


@runtime_checkable
class FingerprintConnector(DeviceConnector, Protocol):
    async def enroll(self, ctx: ConnectorContext, *, subject_ref: str) -> ConnectorResult: ...

    async def verify(self, ctx: ConnectorContext, *, subject_ref: str) -> ConnectorResult: ...


@runtime_checkable
class FaceRecognitionConnector(DeviceConnector, Protocol):
    async def enroll(self, ctx: ConnectorContext, *, subject_ref: str) -> ConnectorResult: ...

    async def verify(self, ctx: ConnectorContext, *, subject_ref: str) -> ConnectorResult: ...


@runtime_checkable
class TurnstileConnector(DeviceConnector, Protocol):
    async def open(self, ctx: ConnectorContext, *, direction: str = "in") -> ConnectorResult: ...

    async def lock(self, ctx: ConnectorContext) -> ConnectorResult: ...


@runtime_checkable
class DoorControllerConnector(DeviceConnector, Protocol):
    async def unlock(self, ctx: ConnectorContext, *, duration_seconds: int = 3) -> ConnectorResult: ...

    async def lock(self, ctx: ConnectorContext) -> ConnectorResult: ...


@runtime_checkable
class PaymentTerminalConnector(DeviceConnector, Protocol):
    """Payment terminal adapter — settles via Accounting/Payment platforms later."""

    async def charge(
        self, ctx: ConnectorContext, *, amount: int, currency: str, reference: str
    ) -> ConnectorResult: ...

    async def refund(
        self, ctx: ConnectorContext, *, amount: int, currency: str, reference: str
    ) -> ConnectorResult: ...


@runtime_checkable
class AttendanceDeviceConnector(DeviceConnector, Protocol):
    async def check_in(
        self, ctx: ConnectorContext, *, subject_ref: str, method: str
    ) -> ConnectorResult: ...

    async def check_out(
        self, ctx: ConnectorContext, *, subject_ref: str, method: str
    ) -> ConnectorResult: ...


class ConnectorRegistry:
    """In-process adapter registry. Vendor adapters register by adapter_key."""

    def __init__(self) -> None:
        self._adapters: dict[str, DeviceConnector] = {}

    def register(self, connector: DeviceConnector) -> None:
        self._adapters[connector.adapter_key] = connector

    def get(self, adapter_key: str) -> DeviceConnector | None:
        return self._adapters.get(adapter_key)

    def list_by_capability(self, capability: ConnectorCapability) -> list[DeviceConnector]:
        return [c for c in self._adapters.values() if c.capability == capability]

    def keys(self) -> list[str]:
        return sorted(self._adapters.keys())


_default_registry = ConnectorRegistry()


def get_connector_registry() -> ConnectorRegistry:
    return _default_registry


def reset_connector_registry() -> ConnectorRegistry:
    global _default_registry
    _default_registry = ConnectorRegistry()
    return _default_registry
