import logging
from abc import ABC

from intranet.trip.src.api.auth import LazyRolesMap
from intranet.trip.src.logic.base import Action
from intranet.trip.src.logic.persons import (
    PersonalDataGateway,
    get_personal_data_gateway,
)
from intranet.trip.src.models import User
from intranet.trip.src.models.employee import Approver, Employee, EmployeeActions
from intranet.trip.src.unit_of_work import UnitOfWork

logger = logging.getLogger(__name__)


async def complement_employees(uow: UnitOfWork, employees: list, user: User) -> list[Employee]:
    pdg: PersonalDataGateway = await get_personal_data_gateway(uow)
    roles_map = LazyRolesMap(uow, person_ids=[e.employee_id for e in employees])
    for employee in employees:
        # TODO: when suggest service will be released we can get fullname from suggest
        # TODO: get_persons - for get persons with one request to DB/suggest
        person = await pdg.get_person(person_id=employee.employee_id)
        employee.first_name = person.first_name
        employee.last_name = person.last_name
        employee.middle_name = person.middle_name
        employee.actions = await get_employees_actions(
            uow=uow,
            user=user,
            employee=employee,
        )
        approver_ids = await roles_map.get_approver_ids(employee.employee_id)
        if len(approver_ids) > 1:
            logger.warning(f'Too many approvers for {employee.employee_id}')
        # FIXME: it is necessary to raise an WorkflowError if there are no approvers
        #        but now for each employees we get ourselves
        approver = await uow.persons.get_person(person_id=employee.employee_id)
        # TODO: when suggest service will be released we can get fullname from suggest
        # TODO: get_persons - for get persons with one request to DB/suggest
        person = await pdg.get_person(person_id=approver.person_id)
        employee.approver = Approver(
            approver_id=approver.person_id,
            first_name=person.first_name,
            last_name=person.last_name,
            middle_name=person.middle_name,
        )
    return employees


class EmployeeAction(Action, ABC):
    def __init__(
        self,
        uow: UnitOfWork,
        user: User,
        employee: Employee,
    ):
        self.uow = uow
        self.user = user
        self.employee = employee


class ActivateAction(EmployeeAction):
    """ Accept activation for account """

    action_name = 'activate'

    async def check_permissions(self) -> None:
        pass

    async def execute(self, *args, **kwargs):
        pass


class RejectAction(EmployeeAction):
    """ Reject activation for account """

    action_name = 'reject'

    async def check_permissions(self) -> None:
        pass

    async def execute(self, *args, **kwargs):
        pass


class BlockAction(EmployeeAction):
    """ Block accesses to service for a user """

    action_name = 'block'

    async def check_permissions(self) -> None:
        pass

    async def execute(self, *args, **kwargs):
        pass


class RestoreAction(EmployeeAction):
    """ Open accesses to service for a user """

    action_name = 'restore'

    async def check_permissions(self) -> None:
        pass

    async def execute(self, *args, **kwargs):
        pass


class GrantCoordinatorAction(EmployeeAction):
    """ Grant coordinator role """

    action_name = 'grant_coordinator'

    async def check_permissions(self) -> None:
        pass

    async def execute(self, *args, **kwargs):
        pass


class RevokeCoordinatorAction(EmployeeAction):
    """ Revoke coordinator role """

    action_name = 'revoke_coordinator'

    async def check_permissions(self) -> None:
        pass

    async def execute(self, *args, **kwargs):
        pass


class ChangeApproverAction(EmployeeAction):
    """ Change approver for a user """

    action_name = 'change_approver'

    async def check_permissions(self) -> None:
        pass

    async def execute(self, *args, **kwargs):
        pass


async def get_employees_actions(
    uow: UnitOfWork,
    user: User,
    employee: Employee,
) -> EmployeeActions:
    data = dict()
    action_classes = [
        ActivateAction,
        RejectAction,
        BlockAction,
        RestoreAction,
        ChangeApproverAction,
    ]

    for action_class in action_classes:
        action = action_class(
            uow=uow,
            user=user,
            employee=employee,
        )
        data[action.action_name] = await action.is_available()
    return EmployeeActions(**data)
