import { BaseAdapter, ErrorCodes, RequestConflictError } from '@humand-packages/common';
import { Service } from 'typedi';
import { PortsDI } from '../../../../../config/portsDI';
import { FeatureFlagCode } from '../../../../featureFlags/business/enums/featureFlagCode';
import { FeatureFlagService } from '../../../../featureFlags/business/services/featureFlagService';
import { TimeTrackingConfigRepositoryPort } from '../../../infrastructure/ports/timeTracking/timeTrackingConfigRepositoryPort';
import TimeTrackingUserSettingRepositoryPort from '../../../infrastructure/ports/timeTracking/timeTrackingUserSettingRepositoryPort';
import { TimeTrackingUserSetting } from '../../models/timeTracking/timeTrackingUserSetting';

@Service()
export default class TimeTrackingUserSettingForUserCreationService extends BaseAdapter {
    constructor(
        @PortsDI(TimeTrackingUserSettingRepositoryPort) private readonly timeTrackingUserSettingRepository: TimeTrackingUserSettingRepositoryPort,
        private readonly featureFlagService: FeatureFlagService,
        @PortsDI(TimeTrackingConfigRepositoryPort) private readonly timeTrackingConfigService: TimeTrackingConfigRepositoryPort,
    ) {
        super();
    }

    public async existsByInstanceIdAndKioskPin(instanceId: number, kioskPin: string, userId?: number): Promise<boolean> {
        return this.timeTrackingUserSettingRepository.existsByInstanceIdAndKioskPin(instanceId, kioskPin, userId);
    }

    public async getByInstanceIdAndKioskPin(instanceId: number, kioskPin: string): Promise<TimeTrackingUserSetting | null> {
        return this.timeTrackingUserSettingRepository.getByInstanceIdAndKioskPin(instanceId, kioskPin);
    }

    public async updateKioskPin(instanceId: number, userId: number, kioskPin: string): Promise<TimeTrackingUserSetting> {
        const normalizedKioskPin = kioskPin.trim() ? kioskPin.trim() : null;
        if (normalizedKioskPin) {
            const alreadyExists = await this.timeTrackingUserSettingRepository.existsByInstanceIdAndKioskPin(instanceId, normalizedKioskPin, userId);
            if (alreadyExists) throw new RequestConflictError('Kiosk PIN already exists', ErrorCodes.TIME_TRACKING_KIOSK_PIN_ALREADY_EXISTS);
        }
        const userSetting = await this.timeTrackingUserSettingRepository.getByInstanceIdAndUserId(instanceId, userId);
        const hasTimeTrackingDesertEagleEnabledFF = await this.getTimeTrackingDesertEagleEnabledFeatureFlag(instanceId);
        if (!userSetting) {
            const newUserSetting = this.timeTrackingUserSettingRepository.create({ instanceId, kioskPin: normalizedKioskPin, userId });
            if (hasTimeTrackingDesertEagleEnabledFF) {
                await this.timeTrackingConfigService.updateUserSetting(instanceId, userId, normalizedKioskPin);
            }
            return newUserSetting;
        } else {
            userSetting.kioskPin = normalizedKioskPin ?? null;
            const updatedUserSetting = await this.timeTrackingUserSettingRepository.update(userSetting);
            if (hasTimeTrackingDesertEagleEnabledFF) {
                await this.timeTrackingConfigService.updateUserSetting(instanceId, userId, normalizedKioskPin);
            }
            return updatedUserSetting;
        }
    }

    public async getMappedKioskPinByUserIds(instanceId: number, userIds: number[]): Promise<Record<number, string>> {
        const userSettings = await this.timeTrackingUserSettingRepository.getByInstanceIdAndUserIds(instanceId, userIds);
        return userSettings.reduce(
            (acc, userSetting) => {
                acc[userSetting.userId] = userSetting.kioskPin ?? '';
                return acc;
            },
            {} as Record<number, string>,
        );
    }

    public async getTimeTrackingUserSetting(instanceId: number, userId: number): Promise<TimeTrackingUserSetting> {
        const userSetting = await this.timeTrackingUserSettingRepository.getByInstanceIdAndUserId(instanceId, userId);
        if (!userSetting) {
            return {
                instanceId,
                kioskPin: null,
                userId,
            } as TimeTrackingUserSetting;
        } else {
            return userSetting;
        }
    }

    private getTimeTrackingDesertEagleEnabledFeatureFlag = async (instanceId: number): Promise<boolean> => {
        const featureFlag = await this.featureFlagService.getBooleanFeatureFlag(FeatureFlagCode.TIME_TRACKING_DESERT_EAGLE_ENABLED, instanceId);
        return featureFlag.value;
    };
}
