import logging

from pyfsense_client.v2.client import PfSenseV2Client
from pyfsense_client.v2.exceptions import ValidationError
from pyfsense_client.v2.models import APIResponse, FirewallAlias

from routers.client.pfsense_v2 import PfSenseV2MetaClient

from ..exceptions import AdapterException
from ..type_conversions import (
    alias_to_pfsense_v2_firewall_alias,
    pfsense_firewall_v2_alias_to_alias,
)
from ..types import Alias
from .base import ClientAliasAdapter

logger = logging.getLogger(__name__)


class PFSenseV2AliasAdapter(ClientAliasAdapter):
    """
    Concrete alias adapter for pfSense V2 API that now utilizes the PfSenseV2MetaClient.
    This greatly simplifies operations by leveraging caching and name-based lookups.
    """

    def __init__(self, client: PfSenseV2Client):
        super().__init__(client)
        # Wrap the underlying client with the meta client.
        self.meta_client = PfSenseV2MetaClient(client)

    def create_alias(self, alias: Alias, apply: bool = True) -> FirewallAlias:
        """
        Create a firewall alias using the meta client.
        """
        try:
            pf_alias_create = alias_to_pfsense_v2_firewall_alias(alias)
            response = self.meta_client.create_firewall_alias(pf_alias_create)
            logger.debug(f"pfSense V2 create_alias response: {response}")

            if apply:
                self.meta_client.apply_firewall_changes()
            return response

        except ValidationError as e:
            raise AdapterException(f"Failed to create alias {alias.name}: {str(e)}") from e

    def update_alias(self, alias: Alias, apply: bool = True) -> FirewallAlias:
        """
        Update an existing firewall alias using the meta client.
        The meta client handles alias lookup and model conversion.
        """
        try:
            response = self.meta_client.update_firewall_alias_by_name(alias)
            logger.debug(f"pfSense V2 update_alias response: {response}")

            if apply:
                self.meta_client.apply_firewall_changes()
            return response

        except ValidationError as e:
            raise AdapterException(f"Failed to update alias {alias.name}: {str(e)}") from e

    def is_alias_in_use(self, alias_name: str) -> bool:
        """
        The pfSense V2 API does not provide a direct endpoint for checking alias usage.
        This method remains unimplemented until such functionality is available.
        """
        raise NotImplementedError("is_alias_in_use method not implemented for pfSense V2.")

    def delete_alias(self, alias_name: str, apply: bool = True) -> dict | APIResponse:
        if self.is_alias_in_use(alias_name):
            response = {"msg": f"Alias {alias_name} is in use. Skipping deletion."}
            logger.debug(response)
            return response

        try:
            response = self.meta_client.delete_firewall_alias_by_name(alias_name)
            logger.debug(f"pfSense V2 delete_alias response: {response}")

            if apply:
                self.meta_client.apply_firewall_changes()
            return response

        except ValidationError as e:
            raise AdapterException(f"Failed to delete alias {alias_name}: {str(e)}") from e

    def rename_alias(self, alias: Alias, new_name: str, apply: bool = True) -> FirewallAlias:
        """
        Rename an existing firewall alias using the meta client.
        We create a new Alias instance with the updated name and delegate the update.
        """
        original_name = alias.name
        updated_alias = Alias(
            name=new_name,
            alias_type=alias.alias_type,
            description=alias.description,
            content=alias.content,
            detail=alias.detail,
        )
        try:
            response = self.meta_client.update_firewall_alias_by_name(updated_alias, original_name=original_name)
            logger.debug(f"pfSense V2 rename_alias response: {response}")

            if apply:
                self.meta_client.apply_firewall_changes()
            return response
        except ValidationError as e:
            raise AdapterException(f"Failed to rename alias {original_name} to {new_name}: {str(e)}") from e

    def get_all_aliases(self) -> list[Alias]:
        """
        Retrieve all firewall aliases using the meta client's public list operation.
        """
        try:
            raw_aliases = self.meta_client.list_aliases()
        except ValidationError as e:
            raise AdapterException("Failed to retrieve aliases: {str(e)}") from e

        return [pfsense_firewall_v2_alias_to_alias(a) for a in raw_aliases]

    def apply(self) -> APIResponse:
        """
        Apply any pending firewall changes via the meta client.
        """
        try:
            return self.meta_client.apply_firewall_changes()
        except ValidationError as e:
            raise AdapterException("Failed to apply firewall changes: {str(e)}") from e
