import { WORKDAYS } from '@humand-packages/common';
import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';
import { HourCategorizationValidDayTypes } from '../../../business/types/hourCategorization/hourCategorizationValidDayTypes';
import { HourCategorizationValidScheduledHours } from '../../../business/types/hourCategorization/hourCategorizationValidScheduledHours';
import { HourCategorizationValueTypes } from '../../../business/types/hourCategorization/hourCategorizationValueTypes';
import { RuleConditionVC } from '../../validationClasses/hourCategorization/rulesVC';

const HOUR_CATEGORIZATION_VALID_DAYS = Object.values(WORKDAYS);
const HOUR_CATEGORIZATION_VALID_DAY_TYPES = Object.values(HourCategorizationValidDayTypes);
const HOUR_CATEGORIZATION_VALID_SCHEDULED_HOURS = Object.values(HourCategorizationValidScheduledHours);
const HOUR_CATEGORIZATION_TIME_REGEX = /^\d{2}:\d{2}$/;

@ValidatorConstraint({ async: false, name: 'isValidHourCategorizationRule' })
export class IsValidHourCategorizationRuleConstraint implements ValidatorConstraintInterface {
    validate(value: unknown, args: ValidationArguments) {
        const obj = args.object as RuleConditionVC;
        const valueType = obj.valueType;
        if (valueType == null || value == null) return false;

        switch (valueType) {
            case HourCategorizationValueTypes.SCHEDULED_HOURS:
                return HOUR_CATEGORIZATION_VALID_SCHEDULED_HOURS.includes(String(value).toUpperCase() as HourCategorizationValidScheduledHours);

            case HourCategorizationValueTypes.NUMBER_OF_HOURS:
                return Number.isInteger(Number(value)) && Number(value) >= 0;

            case HourCategorizationValueTypes.HOURS_TYPE:
                return String(value).toUpperCase() === 'WORKING';

            case HourCategorizationValueTypes.DAY_LIST: {
                let list: string[] = [];
                try {
                    if (typeof value === 'string') list = value.split(',').map((v) => v.trim().toUpperCase());
                    else if (Array.isArray(value)) list = value.map((v) => String(v).toUpperCase());
                    else return false;
                } catch {
                    return false;
                }
                if (list.length === 0) return false;
                const unique = new Set(list);
                if (unique.size !== list.length) return false; // no duplicates
                return list.every((day) => HOUR_CATEGORIZATION_VALID_DAYS.includes(day as WORKDAYS));
            }
            case HourCategorizationValueTypes.DAY_TYPE:
                return HOUR_CATEGORIZATION_VALID_DAY_TYPES.includes(String(value).toUpperCase() as HourCategorizationValidDayTypes);

            case HourCategorizationValueTypes.TIME_RANGE:
                if (!Array.isArray(value) || value.length !== 2) return false;
                const [start, end] = value;
                return (
                    typeof start === 'string' &&
                    typeof end === 'string' &&
                    HOUR_CATEGORIZATION_TIME_REGEX.test(start) &&
                    HOUR_CATEGORIZATION_TIME_REGEX.test(end)
                );

            default:
                return false;
        }
    }

    defaultMessage(args: ValidationArguments) {
        const obj = args.object as RuleConditionVC;
        const valueType = obj.valueType;
        if (valueType == null) return 'Invalid value type';
        return `Invalid value '${JSON.stringify(obj.value)}' for valueType '${valueType}'`;
    }
}
