import {
    CapabilityName,
    FilterableMandatoryPaginableVC,
    validateBodyParams,
    validateSortingParams,
    validateStringQueryParams,
    validateShiftAssignedDayIdPathParam,
    validateShiftAssignedShiftIdPathParam,
    validateIdPathParam,
    validateUUIDPathParamWith,
} from '@humand-packages/common';
import { Router } from 'express';
import Container from 'typedi';
import { validatePageLimitPagination } from '../../../../middlewares/pageLimitPaginationValidator';
import { DeprecatedHumandResponse } from '../../../../types/locals';
import { validateBotAppPermissions } from '../../../auth/presentation/middlewares/jwtAuthenticator';
import { DepartmentDAO } from '../../../departments/infrastructure/dataAccessObjects/departmentDAO';
import { TimeOffRequestApprovalStepDAO } from '../../../timeOff/infrastructure/dataAccessObjects/requests/approvalSteps/timeOffRequestApprovalStepDAO';
import { TimeOffController } from '../../../timeOff/presentation/controllers/timeOffController';
import { GetTimeOffRequestsAppVC } from '../../../timeOff/presentation/validationClasses/getTimeOffRequestsAppVC';
import { UserDAO } from '../../../users/infrastructure/dataAccessObjects/userDAO';
import { FilterPublicUserListMapper } from '../../../users/presentation/validationClasses/filterPublicUserListMapper';
import { ShiftManagementController } from '../controllers/shiftManagement';
import { ShiftRotationController } from '../controllers/shiftRotation';
import { TimeTrackingController } from '../controllers/timeTracking';
import { TimeTrackingHourCategorizationController } from '../controllers/timeTrackingHourCategorization';
import { TimeTrackingPoliciesController } from '../controllers/timeTrackingPolicies';
import { WorkScheduleController } from '../controllers/workSchedule';
import { CreateOfflineTimeTrackingEntriesRequestsVC } from '../validationClasses/createOfflineTimeTrackingEntriesRequestsVC';
import { CreateTimeTrackingEntryRequestsVC } from '../validationClasses/createTimeTrackingEntryRequestsVC';
import { GetDaySummaryDetailVC } from '../validationClasses/getDaySummaryDetailVC';
import { GetTimeTrackingEntryRequestsVC } from '../validationClasses/getTimeTrackingEntryRequestsVC';
import { BulkReviewCategorizedHoursVC } from '../validationClasses/hourCategorization/bulkReviewCategorizedHoursVC';
import { CategorizedHoursFiltersVC } from '../validationClasses/hourCategorization/categorizedHoursFiltersVC';
import { EditCategorizedHourStatusVC } from '../validationClasses/hourCategorization/editCategorizedHourStatusVC';
import { ExplainCategorizationVC } from '../validationClasses/hourCategorization/explainCategorizationVC';
import { GetCategorizedHoursVC } from '../validationClasses/hourCategorization/getCategorizedHoursVC';
import { GetHourCategoriesVC } from '../validationClasses/hourCategorization/GetHourCategoriesVC';
import { ReviewCategorizedHourApprovalStepVC } from '../validationClasses/hourCategorization/reviewCategorizedHourApprovalStepVC';
import { UpdateCategorizedHourVC } from '../validationClasses/hourCategorization/updateCategorizedHourVC';
import { AssignShiftRotationVC } from '../validationClasses/shiftManagement/assignShiftRotationVC';
import { CreateOrUpdateShiftRotationVC } from '../validationClasses/shiftManagement/createOrUpdateShiftRotationVC';
import { DuplicateShiftPeriodVC } from '../validationClasses/shiftManagement/duplicateShiftPeriodVC';
import { GetRegionsVC } from '../validationClasses/shiftManagement/getRegionsVC';
import { ShiftAssignRequestVC } from '../validationClasses/shiftManagement/shiftAssignVC';
import { ShiftBulkDeleteVC } from '../validationClasses/shiftManagement/shiftBulkDeleteVC';
import { ShiftCopyAndPasteVC } from '../validationClasses/shiftManagement/shiftCopyAndPasteVC';
import { ShiftManagementCalendarFiltersVC } from '../validationClasses/shiftManagement/shiftManagementCalendarFiltersVC';
import { ShiftManagementUsersFiltersVC } from '../validationClasses/shiftManagement/shiftManagementUsersFiltersVC';
import { ShiftMoveVC } from '../validationClasses/shiftManagement/shiftMoveVC';
import { ShiftMyCalendarVC } from '../validationClasses/shiftManagement/shiftMyCalendar';
import { ShiftRotationsListFiltersVC } from '../validationClasses/shiftManagement/shiftRotationsListFiltersVC';
import { ShiftsListFiltersVC } from '../validationClasses/shiftManagement/shiftsListFiltersVC';
import { ShiftTemplateVC } from '../validationClasses/shiftManagement/shiftTemplateVC';
import { TimeTrackingGetNotificationScheduleVC } from '../validationClasses/timeTracking/timeTrackingGetNotificationScheduleVC';
import {
    TimeTrackingDaySummaryWithReportFiltersVC,
    TimeTrackingDaySummaryWithScheduleFiltersVC,
} from '../validationClasses/timeTrackingDaySummaryFiltersVC';
import { UpdateTimeTrackingEntryRequestsVC } from '../validationClasses/updateTimeTrackingEntryRequestsVC';

export function startTimeTrackingAppRouter(paginationMaxLimit: number): Router {
    const timeTrackingController = Container.get(TimeTrackingController);
    const policiesController = Container.get(TimeTrackingPoliciesController);
    const timeOffController = Container.get(TimeOffController);
    const timeTrackingHourCategorizationController = Container.get(TimeTrackingHourCategorizationController);
    const router = Router();
    router.get(
        '/entries',
        validatePageLimitPagination({ required: false }),
        validateStringQueryParams(GetTimeTrackingEntryRequestsVC),
        validateBotAppPermissions([CapabilityName.VIEW_TIME_TRACKING]),
        timeTrackingController.listEntries,
    );
    router.post(
        '/entries',
        validateBodyParams(CreateTimeTrackingEntryRequestsVC),
        validateBotAppPermissions([CapabilityName.VIEW_TIME_TRACKING]),
        timeTrackingController.createEntry,
    );
    router.put('/entries', validateBodyParams(UpdateTimeTrackingEntryRequestsVC), timeTrackingController.updateEntries);
    router.post(
        '/entries/sync',
        validateBodyParams(CreateOfflineTimeTrackingEntriesRequestsVC),
        validateBotAppPermissions([CapabilityName.VIEW_TIME_TRACKING]),
        timeTrackingController.syncEntries,
    );
    router.get('/day-summary', validateBotAppPermissions([CapabilityName.VIEW_TIME_TRACKING]), timeTrackingController.getRecentDaySummary);
    router.get(
        '/day-summaries/detail',
        validateStringQueryParams(GetDaySummaryDetailVC),
        validateBotAppPermissions([CapabilityName.VIEW_TIME_TRACKING]),
        timeTrackingController.getDaySummaryDetail,
    );
    router.get(
        '/day-summaries',
        validatePageLimitPagination({ required: true }),
        validateStringQueryParams(TimeTrackingDaySummaryWithScheduleFiltersVC),
        timeTrackingController.listEmployeeSummaries,
    );
    router.get('/report-async', validateStringQueryParams(TimeTrackingDaySummaryWithReportFiltersVC), timeTrackingController.reportToEmail);
    router.get('/policies', policiesController.getPolicyByUser);

    router.get(
        '/time-off-requests',
        validatePageLimitPagination({ maxLimit: paginationMaxLimit, required: true }),
        validateSortingParams(TimeOffRequestApprovalStepDAO),
        validateStringQueryParams(GetTimeOffRequestsAppVC),
        (req, res, next) => timeOffController.listRequests(req, res as DeprecatedHumandResponse, next, true),
    );

    router.get(
        '/notification-schedules',
        validateStringQueryParams(TimeTrackingGetNotificationScheduleVC),
        timeTrackingController.listNotificationSchedule,
    );

    router.get(
        '/departments',
        validateStringQueryParams(FilterableMandatoryPaginableVC),
        validatePageLimitPagination({ required: true }),
        validateSortingParams(DepartmentDAO),
        timeTrackingController.listDepartments,
    );
    router.get(
        '/users',
        validateStringQueryParams(FilterPublicUserListMapper),
        validatePageLimitPagination(),
        validateSortingParams(UserDAO),
        timeTrackingController.listUsers,
    );
    router.get('/regions', validatePageLimitPagination({ required: true }), timeTrackingController.listRegions);
    router.get('/user-setting', timeTrackingController.getMyUserSetting);
    router.get('/grants', timeTrackingController.appGetGrants);

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

    router.get(
        '/categorized-hours/explain',
        validateStringQueryParams(ExplainCategorizationVC),
        timeTrackingHourCategorizationController.explainCategorization,
    );
    router.get('/categorized-hours/pending-amount', timeTrackingHourCategorizationController.getPendingAmount);
    router.get(
        '/categorized-hours',
        validatePageLimitPagination({ required: true }),
        validateStringQueryParams(GetCategorizedHoursVC),
        timeTrackingHourCategorizationController.listCategorizedHours,
    );
    router.post(
        '/categorized-hours/bulk-review',
        validateBodyParams(BulkReviewCategorizedHoursVC),
        timeTrackingHourCategorizationController.bulkReviewCategorizedHours,
    );
    router.get(
        '/categorized-hours/category-counts',
        validateStringQueryParams(CategorizedHoursFiltersVC),
        timeTrackingHourCategorizationController.getCategorizedHourCategoryCounts,
    );
    router.get(
        '/categorized-hours/:categorizedHourId',
        (req, res, next) => validateUUIDPathParamWith('categorizedHourId')(req, res, next),
        timeTrackingHourCategorizationController.getCategorizedHour,
    );
    router.patch(
        '/categorized-hours/:categorizedHourId',
        (req, res, next) => validateUUIDPathParamWith('categorizedHourId')(req, res, next),
        validateBodyParams(UpdateCategorizedHourVC),
        timeTrackingHourCategorizationController.updateCategorizedHour,
    );
    router.patch(
        '/categorized-hours/:categorizedHourId/status',
        (req, res, next) => validateUUIDPathParamWith('categorizedHourId')(req, res, next),
        validateBodyParams(EditCategorizedHourStatusVC),
        timeTrackingHourCategorizationController.editCategorizedHourStatus,
    );
    router.put(
        '/categorized-hours/:categorizedHourId/approval-steps/:approvalStepId/state',
        (req, res, next) => validateUUIDPathParamWith('categorizedHourId')(req, res, next),
        (req, res, next) => validateUUIDPathParamWith('approvalStepId')(req, res, next),
        validateBodyParams(ReviewCategorizedHourApprovalStepVC),
        timeTrackingHourCategorizationController.reviewCategorizedHourApprovalStep,
    );
    // DEPRECATED
    router.get('/report', validateStringQueryParams(TimeTrackingDaySummaryWithReportFiltersVC), timeTrackingController.report);
    return router;
}

export function startWorkScheduleAppRouter(): Router {
    const scheduleController = Container.get(WorkScheduleController);
    const router = Router();
    router.get('/user', scheduleController.getScheduleByUser);
    return router;
}

export function startTimeTrackingPoliciesAppRouter(): Router {
    const policiesController = Container.get(TimeTrackingPoliciesController);
    const router = Router();
    router.get('/policies', policiesController.getPolicyByUser);
    return router;
}

export function startShiftsAppRouter(): Router {
    const shiftsController = Container.get(ShiftManagementController);
    const router = Router();

    router.get(
        '/templates',
        validatePageLimitPagination({ required: true }),
        validateStringQueryParams(ShiftsListFiltersVC),
        shiftsController.getShifts,
    );

    router.post('/templates', validateBodyParams(ShiftTemplateVC), shiftsController.createShiftTemplate);
    router.put('/templates/:id', validateIdPathParam, validateBodyParams(ShiftTemplateVC), shiftsController.updateShiftTemplate);
    router.delete('/templates/:id', validateIdPathParam, shiftsController.deleteShiftTemplate);

    router.delete(
        '/:shiftAssignedDayId/assignments/:shiftAssignedShiftId',
        validateShiftAssignedDayIdPathParam,
        validateShiftAssignedShiftIdPathParam,
        shiftsController.deleteAssignedShift,
    );
    router.get(
        '/calendar',
        validatePageLimitPagination({ required: true }),
        validateStringQueryParams(ShiftManagementCalendarFiltersVC),
        shiftsController.calendar,
    );

    router.get('/calendar/me', validateStringQueryParams(ShiftMyCalendarVC), shiftsController.myCalendar);

    router.get(
        '/users',
        validatePageLimitPagination({ required: true }),
        validateStringQueryParams(ShiftManagementUsersFiltersVC),
        shiftsController.listUsers,
    );

    router.post('/assign', validateBodyParams(ShiftAssignRequestVC), shiftsController.assign);
    router.post('/bulk-delete', validateBodyParams(ShiftBulkDeleteVC), shiftsController.bulkDelete);
    router.post('/copy-and-paste', validateBodyParams(ShiftCopyAndPasteVC), shiftsController.copyAndPaste);
    router.post('/move', validateBodyParams(ShiftMoveVC), shiftsController.move);
    router.post('/duplicate-period', validateBodyParams(DuplicateShiftPeriodVC), shiftsController.duplicateShiftPeriod);

    router.get('/regions', validatePageLimitPagination({ required: true }), validateStringQueryParams(GetRegionsVC), shiftsController.getRegions);
    return router;
}

export function startShiftRotationsAppRouter(): Router {
    const controller = Container.get(ShiftRotationController);
    const router = Router();
    const validateIdUUID = validateUUIDPathParamWith('id');

    router.get('/', validatePageLimitPagination({ required: true }), validateStringQueryParams(ShiftRotationsListFiltersVC), controller.list);
    router.post('/', validateBodyParams(CreateOrUpdateShiftRotationVC), controller.create);
    router.get('/:id', validateIdUUID, controller.getById);
    router.put('/:id', validateIdUUID, validateBodyParams(CreateOrUpdateShiftRotationVC), controller.update);
    router.post('/:id/assign', validateIdUUID, validateBodyParams(AssignShiftRotationVC), controller.assign);
    router.delete('/:id', validateIdUUID, controller.delete);

    return router;
}
