import { Op, WhereOptions } from 'sequelize';
import { GridCell, GridFilterRequest } from '../../../../../business/interfaces/shiftManagement/gridFiltersInterface';
import { ShiftAssignedDayStatus } from '../../../../../business/types/shiftAssignedDayStatus';

export const getGridBulkSpecificDatesWhere = (userIds: number[], dates: string[]): WhereOptions => ({
    dateString: dates,
    userId: userIds,
});

export const getGridBulkRangeDatesWhere = (userIds: number[], startDate: string, endDate: string): WhereOptions => ({
    dateString: {
        [Op.between]: [startDate, endDate],
    },
    userId: userIds,
});

export const getGridCellWhere = (cells: GridCell[]): WhereOptions[] =>
    cells.map((cell) => ({
        dateString: cell.date,
        userId: cell.userId,
    }));

export const getGridExcludeCellWhere = (excludeCells: GridCell[]): WhereOptions[] =>
    excludeCells.map((cell) => ({
        [Op.and]: [{ userId: cell.userId }, { dateString: cell.date }],
    }));

export const buildShiftAssignedDayWhere = (instanceId: number, filters: GridFilterRequest): { assignedDaysWhere: WhereOptions | undefined } => {
    const { userIds, dates, startDate, endDate, cells, excludeCells, assignedShiftIds, excludeAssignedShiftIds } = filters;
    const hasBulkFilters = !!(userIds?.length && (dates?.length || (startDate && endDate)));
    const hasCellFilters = !!cells?.length;
    const hasExcludeCellFilters = !!excludeCells?.length;
    const hasAssignedShiftIds = !!assignedShiftIds?.length;
    const hasExcludeAssignedShiftIds = !!excludeAssignedShiftIds?.length;
    const hasDayFilter = hasBulkFilters || hasCellFilters;
    const hasRangeDateFilter = !!startDate && !!endDate;
    const hasSpecificDatesFilter = !!dates?.length;
    if (!(hasDayFilter || hasAssignedShiftIds)) {
        return { assignedDaysWhere: undefined };
    }

    const includeClauses: WhereOptions[] = [];
    if (hasBulkFilters) {
        if (hasSpecificDatesFilter) {
            includeClauses.push(getGridBulkSpecificDatesWhere(userIds, dates));
        } else if (hasRangeDateFilter) {
            includeClauses.push(getGridBulkRangeDatesWhere(userIds, startDate, endDate));
        }
    }
    if (hasCellFilters) {
        includeClauses.push(...getGridCellWhere(cells));
    }

    const assignedShiftIdsClause = hasAssignedShiftIds ? { '$shiftAssociations.id$': { [Op.in]: assignedShiftIds } } : undefined;

    const excludeAssignedShiftIdsClause = hasExcludeAssignedShiftIds
        ? { '$shiftAssociations.id$': { [Op.notIn]: excludeAssignedShiftIds } }
        : undefined;

    const assignedDaysWhere: WhereOptions = {
        instanceId,
        status: ShiftAssignedDayStatus.PUBLISHED,
        ...(excludeAssignedShiftIdsClause ?? {}),
        ...(hasExcludeCellFilters ? { [Op.not]: { [Op.or]: getGridExcludeCellWhere(excludeCells) } } : {}),
        [Op.or]: [...(includeClauses.length ? includeClauses : []), ...(assignedShiftIdsClause ? [assignedShiftIdsClause] : [])],
    };

    return { assignedDaysWhere };
};
