"""Exceptions for security domain-inspired security patterns."""

from __future__ import annotations


class DomainsError(Exception):
    """Base exception for domains module."""


# Template exceptions


class TemplateError(DomainsError):
    """Base exception for template operations."""


class TemplateExistsError(TemplateError):
    """Template already exists."""

    def __init__(self, name: str) -> None:
        self.name = name
        super().__init__(f"Template already exists: {name}")


class TemplateNotFoundError(TemplateError):
    """Template not found."""

    def __init__(self, name: str) -> None:
        self.name = name
        super().__init__(f"Template not found: {name}")


class TemplateInUseError(TemplateError):
    """Template has active instances."""

    def __init__(self, name: str, instance_count: int) -> None:
        self.name = name
        self.instance_count = instance_count
        super().__init__(
            f"Template '{name}' has {instance_count} active instance(s). "
            "Use --force to delete anyway."
        )


class TemplateSpawnError(TemplateError):
    """Failed to spawn instance from template."""

    def __init__(self, template_name: str, instance_name: str, reason: str) -> None:
        self.template_name = template_name
        self.instance_name = instance_name
        self.reason = reason
        super().__init__(
            f"Failed to spawn '{instance_name}' from template '{template_name}': {reason}"
        )


# Disposable exceptions


class DisposableError(DomainsError):
    """Base exception for disposable operations."""


class DisposableExistsError(DisposableError):
    """Disposable configuration already exists."""

    def __init__(self, name: str) -> None:
        self.name = name
        super().__init__(f"Disposable configuration already exists: {name}")


class DisposableNotFoundError(DisposableError):
    """Disposable configuration not found."""

    def __init__(self, name: str) -> None:
        self.name = name
        super().__init__(f"Disposable configuration not found: {name}")


class DisposableLaunchError(DisposableError):
    """Failed to launch disposable instance."""

    def __init__(self, name: str, reason: str) -> None:
        self.name = name
        self.reason = reason
        super().__init__(f"Failed to launch disposable '{name}': {reason}")


# Domain exceptions


class DomainError(DomainsError):
    """Base exception for domain operations."""


class DomainPolicyError(DomainError):
    """Domain policy violation."""

    def __init__(self, domain: str, violation: str) -> None:
        self.domain = domain
        self.violation = violation
        super().__init__(f"Domain '{domain}' policy violation: {violation}")


class InterDomainError(DomainError):
    """Inter-domain communication not allowed."""

    def __init__(self, source_domain: str, target_domain: str) -> None:
        self.source_domain = source_domain
        self.target_domain = target_domain
        super().__init__(
            f"Communication from '{source_domain}' to '{target_domain}' is not allowed"
        )


# Vault exceptions


class VaultError(DomainsError):
    """Base exception for vault operations."""


class VaultExistsError(VaultError):
    """Vault already exists."""

    def __init__(self, name: str) -> None:
        self.name = name
        super().__init__(f"Vault already exists: {name}")


class VaultNotFoundError(VaultError):
    """Vault not found."""

    def __init__(self, name: str) -> None:
        self.name = name
        super().__init__(f"Vault not found: {name}")


class VaultLockedError(VaultError):
    """Vault is locked."""

    def __init__(self, name: str) -> None:
        self.name = name
        super().__init__(f"Vault '{name}' is locked. Unlock it first.")


class VaultOperationDeniedError(VaultError):
    """Operation not allowed by policy."""

    def __init__(
        self, container: str, vault: str, operation: str, reason: str | None = None
    ) -> None:
        self.container = container
        self.vault = vault
        self.operation = operation
        self.reason = reason
        msg = f"Container '{container}' is not allowed to perform '{operation}' on vault '{vault}'"
        if reason:
            msg += f": {reason}"
        super().__init__(msg)


class VaultKeyNotFoundError(VaultError):
    """Key not found in vault."""

    def __init__(self, vault: str, key_id: str) -> None:
        self.vault = vault
        self.key_id = key_id
        super().__init__(f"Key '{key_id}' not found in vault '{vault}'")


class VaultKeyImportError(VaultError):
    """Failed to import key into vault."""

    def __init__(self, vault: str, reason: str) -> None:
        self.vault = vault
        self.reason = reason
        super().__init__(f"Failed to import key into vault '{vault}': {reason}")


class VaultAttachmentError(VaultError):
    """Failed to attach container to vault."""

    def __init__(self, container: str, vault: str, reason: str) -> None:
        self.container = container
        self.vault = vault
        self.reason = reason
        super().__init__(
            f"Failed to attach container '{container}' to vault '{vault}': {reason}"
        )


# Chain exceptions


class ChainError(DomainsError):
    """Base exception for chain operations."""


class ChainExistsError(ChainError):
    """Chain already exists."""

    def __init__(self, name: str) -> None:
        self.name = name
        super().__init__(f"Chain already exists: {name}")


class ChainNotFoundError(ChainError):
    """Chain not found."""

    def __init__(self, name: str) -> None:
        self.name = name
        super().__init__(f"Chain not found: {name}")


class ChainStartError(ChainError):
    """Failed to start chain."""

    def __init__(self, name: str, reason: str) -> None:
        self.name = name
        self.reason = reason
        super().__init__(f"Failed to start chain '{name}': {reason}")


class ChainHopError(ChainError):
    """Error with a specific hop in the chain."""

    def __init__(self, chain: str, hop: str, reason: str) -> None:
        self.chain = chain
        self.hop = hop
        self.reason = reason
        super().__init__(f"Chain '{chain}' hop '{hop}' error: {reason}")
