import {
    validateBodyParams,
    checkExcelMimeTypes,
    getFileMiddlewareByUploadType,
    getHumandUpload,
    validateSortingParams,
    validateStringQueryParams,
    FilterableMandatoryPaginableVC,
    validateUserIdPathParam,
    validateIdPathParam,
    validateNumberPathParam,
} from '@humand-packages/common';
import { Router } from 'express';
import Container from 'typedi';
import { validatePageLimitPagination } from '../../../../middlewares/pageLimitPaginationValidator';
import { DepartmentDAO } from '../../../departments/infrastructure';
import { TimeTrackingController } from '../controllers/timeTracking';
import { TimeTrackingUserSettingController } from '../controllers/timeTracking/timeTrackingUserSetting';
import { TimeTrackingHourCategorizationController } from '../controllers/timeTrackingHourCategorization';
import { TimeTrackingKioskController } from '../controllers/timeTrackingKiosk';
import { TimeTrackingKioskLinkController } from '../controllers/timeTrackingKioskLink';
import { TimeTrackingPoliciesController } from '../controllers/timeTrackingPolicies';
import { TimeTrackingSettingController } from '../controllers/timeTrackingSetting';
import { WorkScheduleController } from '../controllers/workSchedule';
import AssignUserPoliciesVC from '../validationClasses/assignUserPolicies';
import { AssignUserWorkScheduleVC } from '../validationClasses/assignUserWorkScheduleVC';
import { BulkUpdateWorkScheduleVC } from '../validationClasses/bulkUpdateWorkScheduleVC';
import { CreateWorkScheduleVC } from '../validationClasses/createScheduleVC';
import { GetWorkSchedulesRequestsVC } from '../validationClasses/getWorkScheduleRequestVC';
import { CreateHourCategoryVC } from '../validationClasses/hourCategorization/createHourCategoryVC';
import { GetHourCategoriesVC } from '../validationClasses/hourCategorization/GetHourCategoriesVC';
import { UpdateHourCategoryVC } from '../validationClasses/hourCategorization/updateHourCategoryVC';
import ListTimeTrackingKiosksVC from '../validationClasses/listTimeTrackingKiosksVC';
import ListTimeTrackingPoliciesVC from '../validationClasses/listTimeTrackingPoliciesVC';
import { TimeTrackingKioskPinBulkUpsertVC } from '../validationClasses/timeTracking/timeTrackingKioskPinBulkUpsertVC';
import { TimeTrackingUserSettingUpdateKioskPinVC } from '../validationClasses/timeTracking/timeTrackingKioskPinUpdateVC';
import { TimeTrackingDaySummaryWithScheduleFiltersVC } from '../validationClasses/timeTrackingDaySummaryFiltersVC';
import { TimeTrackingKioskLinkCodeVC } from '../validationClasses/timeTrackingKioskLinkCodeVC';
import { TimeTrackingKiosksCreationVC } from '../validationClasses/timeTrackingKiosksCreationVC';
import { TimeTrackingKiosksUpdateVC } from '../validationClasses/timeTrackingKiosksUpdateVC';
import { TimeTrackingPoliciesCreationVC } from '../validationClasses/timeTrackingPoliciesCreationVC';
import { TimeTrackingPoliciesUpdateVC } from '../validationClasses/timeTrackingPoliciesUpdateVC';
import { TimeTrackingSettingUpdateVC } from '../validationClasses/timeTrackingSettingUpdateVC';
import { UpdateWorkScheduleVC } from '../validationClasses/updateScheduleVC';
import { UpdateTimeTrackingApprovalUsersVC, UpdateTimeTrackingPolicyApprovalUsersVC } from '../validationClasses/updateTimeTrackingApprovalUsersVC';
import { WorkScheduleUserAssignmentFiltersVC } from '../validationClasses/workScheduleUserAssignmentFiltersVC';

export function startWorkScheduleBackofficeRouter(maxFileSize: number): Router {
    const workScheduleController = Container.get(WorkScheduleController);
    const workSchedulesRouter = Router();

    workSchedulesRouter.post('/', validateBodyParams(CreateWorkScheduleVC), workScheduleController.createSchedule);
    workSchedulesRouter.get(
        '/',
        validatePageLimitPagination({ required: true }),
        validateStringQueryParams(GetWorkSchedulesRequestsVC),
        workScheduleController.listSchedules,
    );
    workSchedulesRouter.get('/bulk', workScheduleController.bulkUpdateWorkSchedulesTemplate);
    workSchedulesRouter.post(
        '/bulk',
        getFileMiddlewareByUploadType(getHumandUpload(maxFileSize))(),
        checkExcelMimeTypes,
        validateBodyParams(BulkUpdateWorkScheduleVC),
        workScheduleController.bulkUpdateWorkSchedules,
    );
    workSchedulesRouter.get('/:id', validateIdPathParam, workScheduleController.getSchedule);
    workSchedulesRouter.delete('/:id', validateIdPathParam, workScheduleController.eliminateSchedule);
    workSchedulesRouter.patch('/:id', validateIdPathParam, validateBodyParams(UpdateWorkScheduleVC), workScheduleController.updateSchedule);
    workSchedulesRouter.get('/user/:id', validateIdPathParam, workScheduleController.getScheduleByUserId);
    workSchedulesRouter.put(
        '/user/:id',
        validateIdPathParam,
        validateStringQueryParams(AssignUserWorkScheduleVC),
        workScheduleController.assignUserToWorkSchedule,
    );
    workSchedulesRouter.delete('/user/:id', validateIdPathParam, workScheduleController.unassignUserFromWorkSchedule);
    workSchedulesRouter.get(
        '/:id/users',
        validatePageLimitPagination({ required: true }),
        validateIdPathParam,
        validateStringQueryParams(WorkScheduleUserAssignmentFiltersVC),
        workScheduleController.getAllUsersAssignedToWorkSchedule,
    );
    workSchedulesRouter.get(
        '/:id/users/:userId/assignments',
        validatePageLimitPagination({ required: true }),
        validateIdPathParam,
        validateUserIdPathParam,
        workScheduleController.getAllUserAssignmentsInWorkSchedule,
    );
    workSchedulesRouter.delete(
        '/:workScheduleId/assignment/:id',
        (req, res, next) => validateNumberPathParam(req, res, next, 'workScheduleId'),
        validateIdPathParam,
        workScheduleController.deleteWorkScheduleUser,
    );
    return workSchedulesRouter;
}

export function startTimeTrackingBackofficeRouter(): Router {
    const timeTrackingController = Container.get(TimeTrackingController);
    const timeTrackingRouter = Router();
    timeTrackingRouter.get(
        '/calendar',
        validatePageLimitPagination({ required: true }),
        validateStringQueryParams(TimeTrackingDaySummaryWithScheduleFiltersVC),
        timeTrackingController.listEmployeesCalendar,
    );
    timeTrackingRouter.get(
        '/departments',
        validateStringQueryParams(FilterableMandatoryPaginableVC),
        validatePageLimitPagination({ required: true }),
        validateSortingParams(DepartmentDAO),
        timeTrackingController.listDepartments,
    );
    timeTrackingRouter.get('/regions', validatePageLimitPagination({ required: true }), timeTrackingController.listRegions);
    startTimeTrackingPoliciesBORouter(timeTrackingRouter);
    startTimeTrackingKioskBORouter(timeTrackingRouter);
    startTimeTrackingSettingsBORouter(timeTrackingRouter);
    startTimeTrackingUserSettingsBORouter(timeTrackingRouter);
    startTimeTrackingHourCategorizationBORouter(timeTrackingRouter);
    return timeTrackingRouter;
}

function startTimeTrackingPoliciesBORouter(router: Router) {
    const controller = Container.get(TimeTrackingPoliciesController);
    // Approval users routes (must be registered BEFORE /policies/:id to avoid Express matching "approval-users" as :id)
    router.get('/policies/approval-users', controller.getGlobalApprovalUsers);
    router.put('/policies/approval-users', validateBodyParams(UpdateTimeTrackingApprovalUsersVC), controller.updateGlobalApprovalUsers);
    router.get(
        '/policies',
        validateStringQueryParams(ListTimeTrackingPoliciesVC),
        validatePageLimitPagination({ required: true }),
        controller.listPolicies,
    );
    router.post('/policies', validateBodyParams(TimeTrackingPoliciesCreationVC), controller.createPolicy);
    router.get('/policies/:id', validateIdPathParam, controller.getPolicyById);
    router.get(
        '/policies/:id/hour-categories',
        validateIdPathParam,
        validateStringQueryParams(GetHourCategoriesVC),
        validatePageLimitPagination({ required: true }),
        controller.getPolicyHourCategories,
    );
    router.patch('/policies/:id', validateIdPathParam, validateBodyParams(TimeTrackingPoliciesUpdateVC), controller.updatePolicy);
    router.put('/policies/:id/assignUsers', validateIdPathParam, validateBodyParams(AssignUserPoliciesVC), controller.assignUsersToPolicy);
    router.get('/policies/:id/approval-users', validateIdPathParam, controller.getPolicyApprovalUsers);
    router.put(
        '/policies/:id/approval-users',
        validateIdPathParam,
        validateBodyParams(UpdateTimeTrackingPolicyApprovalUsersVC),
        controller.updatePolicyApprovalUsers,
    );
    router.delete('/policies/:id', validateIdPathParam, controller.eliminatePolicy);
}

function startTimeTrackingKioskBORouter(router: Router) {
    const controller = Container.get(TimeTrackingKioskController);
    const linkController = Container.get(TimeTrackingKioskLinkController);
    router.get('/kiosk', validateStringQueryParams(ListTimeTrackingKiosksVC), validatePageLimitPagination({ required: true }), controller.list);
    router.post('/kiosk', validateBodyParams(TimeTrackingKiosksCreationVC), controller.create);
    router.get('/kiosk/:id', validateIdPathParam, controller.getById);
    router.patch('/kiosk/:id', validateIdPathParam, validateBodyParams(TimeTrackingKiosksUpdateVC), controller.update);
    router.delete('/kiosk/:id', validateIdPathParam, controller.eliminate);
    router.put('/kiosk/:id/link-code', validateIdPathParam, validateBodyParams(TimeTrackingKioskLinkCodeVC), linkController.linkCode);
    router.put('/kiosk/:id/unlink', validateIdPathParam, controller.unLink);
}

function startTimeTrackingSettingsBORouter(router: Router) {
    const controller = Container.get(TimeTrackingSettingController);
    router.get('/settings', controller.getByInstanceId);
    router.patch('/settings', validateBodyParams(TimeTrackingSettingUpdateVC), controller.update);
}

function startTimeTrackingUserSettingsBORouter(router: Router) {
    const controller = Container.get(TimeTrackingUserSettingController);
    router.get('/user-settings/:userId', validateUserIdPathParam, controller.getByUserId);
    router.patch(
        '/user-settings/:userId/kiosk-pin',
        validateUserIdPathParam,
        validateBodyParams(TimeTrackingUserSettingUpdateKioskPinVC),
        controller.updateKioskPin,
    );
    router.put('/user-settings/bulk-upsert', validateBodyParams(TimeTrackingKioskPinBulkUpsertVC), controller.bulkUpsert);
}

function startTimeTrackingHourCategorizationBORouter(router: Router) {
    const controller = Container.get(TimeTrackingHourCategorizationController);
    router.post('/hour-categories', validateBodyParams(CreateHourCategoryVC), controller.createHourCategory);

    router.get(
        '/hour-categories',
        validateStringQueryParams(GetHourCategoriesVC),
        validatePageLimitPagination({ required: true }),
        controller.listHourCategories,
    );
    router.get('/hour-categories/:id', validateIdPathParam, controller.getHourCategory);

    router.put('/hour-categories/:id', validateIdPathParam, validateBodyParams(UpdateHourCategoryVC), controller.updateHourCategory);
    router.delete('/hour-categories/:id', validateIdPathParam, controller.deleteHourCategory);
}
