from __future__ import annotations

import secrets
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Literal

from ..secrets import SecretStore

CredentialScope = Literal["BYOK", "Resell"]


@dataclass(slots=True)
class CredentialRecord:
    """Persisted credential metadata resolved via the CredentialStore."""

    id: str
    provider: str
    scope: CredentialScope
    credential_ref: str
    org_id: str | None = None
    key_preview: str | None = None
    status: str = "active"


class CredentialStore(ABC):
    """Interface for BYOK and resell credential registries."""

    @abstractmethod
    def upsert(self, record: CredentialRecord) -> None:
        """Create or update a credential record."""

    @abstractmethod
    def list(
        self, *, org_id: str | None = None, provider: str | None = None
    ) -> list[CredentialRecord]:
        """Return credentials filtered by org or provider (if provided)."""

    @abstractmethod
    def deactivate(self, credential_id: str) -> None:
        """Mark a credential as inactive."""


class InMemoryCredentialStore(CredentialStore):
    """In-memory registry for tests and local development."""

    def __init__(self, secret_store: SecretStore | None = None) -> None:
        from ..secrets import InMemorySecretStore

        self._secret_store = secret_store or InMemorySecretStore()
        self._records: dict[str, CredentialRecord] = {}

    def upsert(self, record: CredentialRecord) -> None:
        self._records[record.id] = record

    def list(
        self, *, org_id: str | None = None, provider: str | None = None
    ) -> list[CredentialRecord]:
        records = list(self._records.values())
        if org_id is not None:
            records = [r for r in records if r.org_id == org_id]
        if provider is not None:
            records = [r for r in records if r.provider == provider]
        return [r for r in records if r.status == "active"]

    def deactivate(self, credential_id: str) -> None:
        record = self._records.get(credential_id)
        if record:
            record.status = "inactive"

    def put_secret(
        self,
        provider: str,
        plaintext: str,
        *,
        scope: CredentialScope = "Resell",
        org_id: str | None = None,
        key_preview: str | None = None,
    ) -> CredentialRecord:
        """Helper to create a credential record by storing the secret first."""

        handle = self._secret_store.put(plaintext)
        record = CredentialRecord(
            id=f"cred_{secrets.token_hex(8)}",
            provider=provider,
            scope=scope,
            credential_ref=handle,
            org_id=org_id,
            key_preview=key_preview,
        )
        self.upsert(record)
        return record


__all__ = [
    "CredentialStore",
    "InMemoryCredentialStore",
    "CredentialRecord",
    "CredentialScope",
]
