from typing import Iterable

from sqlalchemy.orm import Session
from sqlalchemy.orm.query import Query

from sqlalchemy import or_

from watcher.enums import MemberState
from watcher.db import Member, Role, Composition, Shift


def query_target_composition_staff(
    db: Session, composition: Composition, staff: Iterable,
    roles: Iterable, scopes: Iterable, excluded_staff: Iterable,
    excluded_roles: Iterable, excluded_scopes: Iterable,
) -> Query:
    """
    Возвращает id Staff состоящих в нужном сервисе и
    отвечающих переданным ролям/скоупам/конкретным людям
    """
    query = query_target_composition_staff_excluded(
        db=db, composition=composition, excluded_staff=excluded_staff,
        excluded_roles=excluded_roles, excluded_scopes=excluded_scopes
    )
    return query.filter(
        or_(
            Member.staff_id.in_(staff),
            Member.role_id.in_(roles),
            Role.scope_id.in_(scopes),
        )
    )


def query_target_composition_staff_excluded(
    db: Session, composition: Composition, excluded_staff: Iterable,
    excluded_roles: Iterable, excluded_scopes: Iterable,
) -> Query:
    """
    Возвращает весь состав сервиса за исключением указанных
    в исключениях
    """
    return (
        db.query(Member.staff_id)
        .join(Role, Role.id == Member.role_id)
        .filter(
            Member.state == MemberState.active,
            Member.service_id == composition.service_id,
            Member.staff_id.notin_(excluded_staff),
            Member.role_id.notin_(excluded_roles),
            Role.scope_id.notin_(excluded_scopes),
        )
    )


def get_member_by_shift(db: Session, shift: Shift) -> Member:
    return db.query(Member).filter(
        Member.state==MemberState.active,
        Member.role_id==shift.slot.role_on_duty_id,
        Member.staff_id==shift.staff_id,
        Member.service_id==shift.schedule.service_id,
        Member.from_department_id.is_(None),
    ).first()


def query_members_in_service_by_staff(db: Session, staff_ids: Iterable[int], service_id: int) -> Query:
    return db.query(Member).filter(
        Member.staff_id.in_(staff_ids),
        Member.service_id == service_id,
        Member.state == MemberState.active,
    )


def is_user_has_specific_role_in_service(db: Session, role_ids: list[int], staff_id: int, service_id: int) -> bool:
    return db.query(
        db.query(Member)
        .filter(Member.staff_id == staff_id)
        .filter(Member.service_id == service_id)
        .filter(Member.role_id.in_(role_ids))
        .exists()
    ).scalar()
