import logging
from typing import Tuple, List

from spaceone.core.manager import BaseManager
from spaceone.core.connector.space_connector import SpaceConnector
from spaceone.identity.model.service_account.database import ServiceAccount

_LOGGER = logging.getLogger(__name__)


class ServiceAccountManager(BaseManager):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.service_account_model = ServiceAccount

    def create_service_account(self, params: dict) -> ServiceAccount:
        def _rollback(vo: ServiceAccount):
            _LOGGER.info(f'[create_service_account._rollback] '
                         f'Delete service account: {vo.name} ({vo.service_account_id})')
            service_account_vo.delete()

        service_account_vo = self.service_account_model.create(params)
        self.transaction.add_rollback(_rollback, service_account_vo)

        return service_account_vo

    def update_service_account(self, params: dict) -> ServiceAccount:
        service_account_vo = self.get_service_account(
            params['service_account_id'],
            params['domain_id'],
            params['workspace_id'],
            params.get('user_projects')
        )

        return self.update_service_account_by_vo(params, service_account_vo)

    def update_service_account_by_vo(self, params: dict, service_account_vo: ServiceAccount) -> ServiceAccount:
        def _rollback(old_data):
            _LOGGER.info(f'[update_service_account_by_vo._rollback] Revert Data : '
                         f'{old_data["service_account_id"]}')
            service_account_vo.update(old_data)

        self.transaction.add_rollback(_rollback, service_account_vo.to_dict())

        return service_account_vo.update(params)

    @staticmethod
    def delete_service_account_by_vo(service_account_vo: ServiceAccount) -> None:
        service_account_vo.delete()

    def get_service_account(
        self, service_account_id: str, domain_id: str, workspace_id: str, user_projects: List[str] = None,
    ) -> ServiceAccount:

        conditions = {
            'service_account_id': service_account_id,
            'domain_id': domain_id,
            'workspace_id': workspace_id,
        }

        if user_projects:
            conditions['project_id'] = user_projects

        return self.service_account_model.get(**conditions)

    def filter_service_accounts(self, **conditions) -> List[ServiceAccount]:
        return self.service_account_model.filter(**conditions)

    def list_service_accounts(self, query: dict) -> Tuple[list, int]:
        return self.service_account_model.query(**query)

    def stat_service_accounts(self, query: dict) -> dict:
        return self.service_account_model.stat(**query)

    def update_secret_project(
        self, service_account_id: str, domain_id: str, workspace_id: str, project_id: str
    ) -> None:
        secret_connector = SpaceConnector(service='secret')
        response = self._list_secrets(secret_connector, service_account_id, domain_id, workspace_id)

        for secret_info in response.get('results', []):
            secret_connector.dispatch('Secret.update', {
                'secret_id': secret_info['secret_id'],
                'project_id': project_id,
                'domain_id': domain_id,
                'workspace_id': workspace_id
            })

    def delete_secrets(
        self, service_account_id: str, domain_id: str, workspace_id: str
    ) -> None:
        secret_connector = SpaceConnector(service='secret')
        response = self._list_secrets(secret_connector, service_account_id, domain_id, workspace_id)

        for secret_info in response.get('results', []):
            secret_connector.dispatch('Secret.delete', {
                'secret_id': secret_info['secret_id'],
                'domain_id': domain_id,
                'workspace_id': workspace_id
            })

    @staticmethod
    def get_all_service_account_ids_using_secret(domain_id: str, workspace_id: str) -> List[str]:
        secret_connector = SpaceConnector(service='secret')
        response = secret_connector.dispatch('Secret.stat', {
            'query': {
                'distinct': 'service_account_id',
                'filter': [
                    {
                        'k': 'service_account_id',
                        'v': None,
                        'o': 'not'
                    }
                ]
            },
            'domain_id': domain_id,
            'workspace_id': workspace_id
        })

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

    @staticmethod
    def _list_secrets(
            secret_connector: SpaceConnector, service_account_id: str, domain_id: str, workspace_id: str
    ) -> dict:
        return secret_connector.dispatch('Secret.list', {
            'service_account_id': service_account_id,
            'domain_id': domain_id,
            'workspace_id': workspace_id
        })