import { BaseController, LoggerPort } from '@humand-packages/common';
import { NextFunction, Request } from 'express';
import { OK } from 'http-status-codes';
import { DeprecatedHumandResponse } from 'humand-packages/monolith/src/api/types/locals';
import { Service } from 'typedi';
import { PermissionsService } from '../../../../permissions/business/services/permissionsService';
import TimeTrackingFaceAssignmentService from '../../../business/services/timeTracking/timeTrackingFaceAssignment';
import { FaceAssignmentsBulkIndexFacesVC } from '../../validationClasses/timeTracking/faceAssignmentsBulkIndexFacesVC';
import { FaceAssignmentsReconcileVC } from '../../validationClasses/timeTracking/faceAssignmentsReconcileVC';

@Service()
export class TimeTrackingFaceAssignmentController extends BaseController {
    constructor(
        private readonly permissionService: PermissionsService,
        private readonly timeTrackingFaceAssignmentService: TimeTrackingFaceAssignmentService,
        logger: LoggerPort,
    ) {
        super(logger);
    }

    public bulkIndexFaces = async (_req: Request, res: DeprecatedHumandResponse, next: NextFunction): Promise<void> => {
        const { loggedUser } = res.locals;
        const params = res.locals.bodyParams as FaceAssignmentsBulkIndexFacesVC;
        await this.endpointHandlerWithGenerics(next, async () => {
            this.permissionService.validateDevOps(loggedUser);
            const result = await this.timeTrackingFaceAssignmentService.bulkIndexFaces(params.instanceIds, {
                limit: params.limit,
                offset: params.offset,
            });
            res.json(result);
            res.status(OK).end();
        });
    };

    public reconcile = async (_req: Request, res: DeprecatedHumandResponse, next: NextFunction): Promise<void> => {
        const { loggedUser } = res.locals;
        const params = (res.locals.bodyParams ?? {}) as FaceAssignmentsReconcileVC;
        await this.endpointHandlerWithGenerics(next, async () => {
            this.permissionService.validateDevOps(loggedUser);
            // Order matters: delete every stale row FIRST, then enroll what's missing. A changed-photo
            // assignment is deleted by the orphaned pass and re-enrolled with the current reference image
            // by the pending pass (the now-empty site looks "missing" to it). Running pending first would
            // leave the stale row in place — pending only fills sites with no row, it never compares images.
            const orphaned = await this.timeTrackingFaceAssignmentService.reconcileOrphanedAssignments({
                limit: params.limit,
                maxInstances: params.maxInstances,
            });
            const pending = await this.timeTrackingFaceAssignmentService.reconcilePendingAssignments({
                limit: params.limit,
                maxInstances: params.maxInstances,
            });
            res.status(OK).json({ ...orphaned, ...pending });
        });
    };
}
