import logging

from spaceone.core.connector.space_connector import SpaceConnector
from spaceone.core.manager import BaseManager

from spaceone.monitoring.error import *

_LOGGER = logging.getLogger(__name__)


class SecretManager(BaseManager):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.secret_connector: SpaceConnector = self.locator.get_connector(
            "SpaceConnector", service="secret"
        )

    def get_secret_from_resource(self, resource, data_source_vo, domain_id):
        secret = {}

        if data_source_plugin_info := data_source_vo.plugin_info:
            if secret_id := data_source_plugin_info.secret_id:
                secret = self.list_secrets_from_query(
                    {"secret_id": secret_id}, domain_id
                )[0]

        if not secret:
            resource_secrets = []
            for collection_info in resource.get("collection_info", []):
                if secret_id := collection_info.get("secret_id"):
                    resource_secrets.append(secret_id)

            if data_source_vo.capability.get("use_resource_secret", False):
                secret_filter = {
                    "provider": data_source_vo.plugin_info.provider,
                    "supported_schema": data_source_vo.capability.get(
                        "supported_schema", []
                    ),
                    "secrets": resource_secrets,
                }
                secret = self.list_secrets_from_query(secret_filter, domain_id)[0]

        return secret

    def list_secrets(self, query: dict, domain_id: str) -> dict:
        return self.secret_connector.dispatch(
            "Secret.list", {"query": query, "domain_id": domain_id}
        )

    def get_secret_data(self, secret_id, domain_id):
        response = self.secret_connector.dispatch(
            "Secret.get_data", {"secret_id": secret_id, "domain_id": domain_id}
        )
        return response["data"]

    def list_secrets_from_query(self, secret_filter, domain_id, **kwargs):
        secret_query = self._make_query(**secret_filter)
        response = self.list_secrets(secret_query, domain_id)

        if response.get("total_count", 0) == 0:
            resource_id = kwargs.get("resource_id")
            raise ERROR_RESOURCE_SECRETS_NOT_EXISTS(resource_id=resource_id)

        return response.get("results", [])

    def get_secret_data_from_plugin(
        self, plugin_info: dict, capability: dict, domain_id: str
    ) -> (dict, dict):
        plugin_id = plugin_info["plugin_id"]
        secret_id = plugin_info.get("secret_id")
        provider = plugin_info.get("provider")

        use_resource_secret = capability.get("use_resource_secret", False)
        supported_schema = capability.get("supported_schema", [])

        self._check_plugin_secret(use_resource_secret, plugin_info)

        if use_resource_secret:
            secret_query = self._make_query(
                supported_schema=supported_schema, provider=provider
            )
        else:
            secret_query = self._make_query(
                supported_schema=supported_schema, secret_id=secret_id
            )

        response = self.list_secrets(secret_query, domain_id)

        if response.get("total_count", 0) == 0:
            if use_resource_secret:
                raise ERROR_SUPPORTED_SECRETS_NOT_EXISTS(
                    plugin_id=plugin_id, provider=provider
                )
            else:
                raise ERROR_NOT_FOUND(key="plugin_info.secret_id", value=secret_id)

        result = response["results"][0]
        secret_id = result["secret_id"]
        schema_id = result.get("schema_id")

        return self.get_secret_data(secret_id, domain_id), schema_id

    @staticmethod
    def _check_plugin_secret(use_resource_secret: bool, plugin_info: dict) -> None:
        secret_id = plugin_info.get("secret_id")
        provider = plugin_info.get("provider")

        if use_resource_secret:
            if provider is None:
                raise ERROR_REQUIRED_PARAMETER(key="plugin_info.provider")
        else:
            if secret_id is None:
                raise ERROR_REQUIRED_PARAMETER(key="plugin_info.secret_id")

    @staticmethod
    def _make_query(**secret_filter):
        supported_schema = secret_filter.get("supported_schema")
        secret_id = secret_filter.get("secret_id")
        service_account_id = secret_filter.get("service_account_id")
        project_id = secret_filter.get("project_id")
        provider = secret_filter.get("provider")
        secrets = secret_filter.get("secrets")

        query = {"filter": []}

        if supported_schema:
            query["filter"].append({"k": "schema_id", "v": supported_schema, "o": "in"})

        if secret_id:
            query["filter"].append({"k": "secret_id", "v": secret_id, "o": "eq"})

        if provider:
            query["filter"].append({"k": "provider", "v": provider, "o": "eq"})

        if service_account_id:
            query["filter"].append(
                {"k": "service_account_id", "v": service_account_id, "o": "eq"}
            )

        if project_id:
            query["filter"].append({"k": "project_id", "v": project_id, "o": "eq"})

        if secrets:
            query["filter"].append({"k": "secret_id", "v": secrets, "o": "in"})

        return query
