import logging

from fastapi_utils.cbv import cbv
from fastapi_utils.inferring_router import InferringRouter
from sqlalchemy import or_
from sqlalchemy.orm import Query

from watcher.api.routes.base import BaseRoute
from watcher.api.schemas.base import CursorPaginationResponse
from watcher.api.schemas.manual_gap import ManualGapBaseSchema

from watcher import enums
from watcher.db import (
    ManualGapSettingsSchedules,
    ManualGapSettingsServices,
    ManualGapSettings,
    ManualGap,
    Schedule,
    Member,
)
from watcher.logic.exceptions import BadRequest


logger = logging.getLogger(__name__)
router = InferringRouter()


@cbv(router)
class ManualGapRoute(BaseRoute):
    model = ManualGap
    joined_load = ('gap_settings', 'gap_settings.services', 'gap_settings.schedules')
    joined_load_list = ('gap_settings', 'gap_settings.services', 'gap_settings.schedules')

    @router.get('/{gap_id}')
    def retrieve(self, gap_id: int) -> ManualGapBaseSchema:
        return self.get_object(gap_id)

    @router.get('/')
    def list(self) -> CursorPaginationResponse[ManualGapBaseSchema]:
        return self.list_objects()

    def filter_objects(self, query: Query) -> Query:
        service_id = self.filter_params.pop('service_id', None)
        service_id__in = self.filter_params.pop('service_id__in', None)

        if not (service_id or service_id__in):
            raise BadRequest(
                message={
                    'ru': 'Должен быть передан параметр фильтрации service_id',
                    'en': 'The filtering parameter service_id must be passed',
                }
            )
        service_ids = None
        if service_id:
            service_ids = [service_id]
        elif service_id__in:
            service_ids = service_id__in

        query = (
            query
            .join(ManualGapSettings)
            .join(Member, Member.staff_id == ManualGap.staff_id)
            .filter(
                ManualGap.is_active.is_(True),
                Member.service_id.in_(service_ids),
                Member.state == enums.MemberState.active,
                or_(
                    ManualGapSettings.all_services.is_(True),
                    self.session.query(ManualGapSettingsServices).filter(
                        ManualGapSettingsServices.gap_settings_id == ManualGapSettings.id,
                        ManualGapSettingsServices.service_id == Member.service_id,
                    ).exists(),
                    self.session.query(ManualGapSettingsSchedules).join(Schedule).filter(
                        ManualGapSettingsSchedules.gap_settings_id == ManualGapSettings.id,
                        Schedule.service_id == Member.service_id,
                    ).exists(),
                )
            )
            .group_by(ManualGap.id)
        )
        return super().filter_objects(query=query)
