from __future__ import annotations

import logging
from typing import Any

from clarabot_nano_common.common.config.extract.base import AbstractExtractedConfig
from passlib.exc import UnknownHashError

from clarabot_nano.common.crypto.admin_password import ADMIN_PASSWORD_CONTEXT

logger = logging.getLogger(__name__)


class AdminPasswordExtractedConfig(AbstractExtractedConfig):
    def __init__(self, config):
        self._admin_policy = config["local"]["remote_admin_policy"]
        self._admin_password = config["remote"]["admin_password"]  # None or str (not plaintext)

    def can_setup_password(self) -> bool:
        """
        Returns True if admin-policy is restring and there is no password set up yet.
        """
        return self._admin_policy == "restrict" and (
            not isinstance(self._admin_password, str) or not ADMIN_PASSWORD_CONTEXT.identify(self._admin_password)
        )

    def check_admin_password(self, test: Any) -> bool:
        if self._admin_policy == "allow":
            return test is None
        elif self._admin_policy == "restrict" and isinstance(self._admin_password, str):
            if isinstance(test, str):
                try:
                    return ADMIN_PASSWORD_CONTEXT.verify(test.encode("utf-8"), self._admin_password)
                except (ValueError, TypeError, UnknownHashError):
                    logger.exception("Failed to verify admin-password")
                    return False
        return False

    def _matches(self, other: AdminPasswordExtractedConfig) -> bool:
        return self.self_matches(self, other)

    @staticmethod
    def self_matches(a: AdminPasswordExtractedConfig, b: AdminPasswordExtractedConfig):
        return a._admin_policy == b._admin_policy and a._admin_password == b._admin_password
