import { ENV_OPTIONAL_NUMBER_KEYS_MAPPING, SEQUELIZE_INSTANCE_TOKEN } from '@humand-packages/common';
import { Op } from 'sequelize';
import { Sequelize } from 'sequelize-typescript';
import { Inject, Service } from 'typedi';
import { v7 as uuidv7 } from 'uuid';
import { BaseRepositoryAdapter } from '../../../../../dbAdapters/baseRepositoryAdapter';
import { TimeTrackingPolicyApprovalStepsParams } from '../../../business/interfaces/timeTracking/policyApprovalStepsParams';
import {
    TimeTrackingPolicyApprovalStepResponsibleRelation,
    TimeTrackingPolicyApprovalStepResponsibleRelationForCreation,
} from '../../../business/models/policies/approvalSteps/responsibles/relation';
import {
    TimeTrackingPolicyApprovalStepResponsibleSegmentationItem,
    TimeTrackingPolicyApprovalStepResponsibleSegmentationItemForCreation,
} from '../../../business/models/policies/approvalSteps/responsibles/segmentationItem';
import {
    TimeTrackingPolicyApprovalStepResponsibleUser,
    TimeTrackingPolicyApprovalStepResponsibleUserForCreation,
} from '../../../business/models/policies/approvalSteps/responsibles/user';
import {
    TimeTrackingPolicyApprovalStep,
    TimeTrackingPolicyApprovalStepForCreation,
} from '../../../business/models/policies/approvalSteps/timeTrackingPolicyApprovalStep';
import { TimeTrackingPolicyApprovalStepResponsibleRelationDAO } from '../../dataAccessObjects/policies/approvalSteps/responsibles/relation';
import { TimeTrackingPolicyApprovalStepResponsibleSegmentationItemDAO } from '../../dataAccessObjects/policies/approvalSteps/responsibles/segmentationItem';
import { TimeTrackingPolicyApprovalStepResponsibleUserDAO } from '../../dataAccessObjects/policies/approvalSteps/responsibles/user';
import { TimeTrackingPolicyApprovalStepDAO } from '../../dataAccessObjects/policies/approvalSteps/timeTrackingPolicyApprovalStepDAO';
import {
    timeTrackingPolicyApprovalStepResponsibleRelationDAOToModel,
    timeTrackingPolicyApprovalStepResponsibleRelationModelToDAO,
} from '../../mappers/policies/approvalSteps/responsibles/relationMapper';
import {
    timeTrackingPolicyApprovalStepResponsibleSegmentationItemDAOToModel,
    timeTrackingPolicyApprovalStepResponsibleSegmentationItemModelToDAO,
} from '../../mappers/policies/approvalSteps/responsibles/segmentationItemMapper';
import {
    timeTrackingPolicyApprovalStepResponsibleUserDAOToModel,
    timeTrackingPolicyApprovalStepResponsibleUserModelToDAO,
} from '../../mappers/policies/approvalSteps/responsibles/userMapper';
import {
    timeTrackingPolicyApprovalStepDAOToModel,
    timeTrackingPolicyApprovalStepModelToDAO,
} from '../../mappers/policies/approvalSteps/timeTrackingPolicyApprovalStepMapper';
import TimeTrackingPolicyApprovalStepsRepositoryPort from '../../ports/TimeTrackingPolicyApprovalStepsRepositoryPort';

@Service()
export default class TimeTrackingPolicyApprovalStepsRepositoryAdapter
    extends BaseRepositoryAdapter
    implements TimeTrackingPolicyApprovalStepsRepositoryPort
{
    constructor(
        @Inject(ENV_OPTIONAL_NUMBER_KEYS_MAPPING.BULK_CREATE_CHUNK_SIZE) bulkCreateChunkSize: number,
        @Inject(SEQUELIZE_INSTANCE_TOKEN) sequelize: Sequelize,
    ) {
        super(bulkCreateChunkSize, sequelize);
    }

    public listPolicyApprovalSteps = async (params: TimeTrackingPolicyApprovalStepsParams): Promise<TimeTrackingPolicyApprovalStep[]> => {
        const daos = await TimeTrackingPolicyApprovalStepDAO.findAll({
            include: [
                { as: 'responsibleRelations', model: TimeTrackingPolicyApprovalStepResponsibleRelationDAO },
                { as: 'responsibleUsers', model: TimeTrackingPolicyApprovalStepResponsibleUserDAO },
                { as: 'responsibleSegmentationItems', model: TimeTrackingPolicyApprovalStepResponsibleSegmentationItemDAO },
            ],
            order: [['position', 'ASC']],
            where: {
                instanceId: params.instanceId,
                ...(params.policyId !== null ? { policyId: params.policyId } : { policyId: { [Op.is]: null } }),
            },
        });
        return daos.map(timeTrackingPolicyApprovalStepDAOToModel);
    };

    public createPolicyApprovalStep = async (approvalStep: TimeTrackingPolicyApprovalStepForCreation): Promise<TimeTrackingPolicyApprovalStep> => {
        const dao = timeTrackingPolicyApprovalStepModelToDAO(approvalStep);
        dao.id = uuidv7();
        const savedDao = await dao.save();
        return timeTrackingPolicyApprovalStepDAOToModel(savedDao);
    };

    public createPolicyApprovalStepResponsibleUsers = async (
        users: TimeTrackingPolicyApprovalStepResponsibleUserForCreation[],
    ): Promise<TimeTrackingPolicyApprovalStepResponsibleUser[]> => {
        const daos = await TimeTrackingPolicyApprovalStepResponsibleUserDAO.bulkCreate(
            users.map((user) => {
                const dao = timeTrackingPolicyApprovalStepResponsibleUserModelToDAO(user);
                return { ...dao.dataValues, id: uuidv7() };
            }),
        );
        return daos.map(timeTrackingPolicyApprovalStepResponsibleUserDAOToModel);
    };

    public createPolicyApprovalStepResponsibleRelations = async (
        relations: TimeTrackingPolicyApprovalStepResponsibleRelationForCreation[],
    ): Promise<TimeTrackingPolicyApprovalStepResponsibleRelation[]> => {
        const daos = await TimeTrackingPolicyApprovalStepResponsibleRelationDAO.bulkCreate(
            relations.map((relation) => {
                const dao = timeTrackingPolicyApprovalStepResponsibleRelationModelToDAO(relation);
                return { ...dao.dataValues, id: uuidv7() };
            }),
        );
        return daos.map(timeTrackingPolicyApprovalStepResponsibleRelationDAOToModel);
    };

    public createPolicyApprovalStepResponsibleSegmentationItems = async (
        items: TimeTrackingPolicyApprovalStepResponsibleSegmentationItemForCreation[],
    ): Promise<TimeTrackingPolicyApprovalStepResponsibleSegmentationItem[]> => {
        const daos = await TimeTrackingPolicyApprovalStepResponsibleSegmentationItemDAO.bulkCreate(
            items.map((item) => {
                const dao = timeTrackingPolicyApprovalStepResponsibleSegmentationItemModelToDAO(item);
                return { ...dao.dataValues, id: uuidv7() };
            }),
        );
        return daos.map(timeTrackingPolicyApprovalStepResponsibleSegmentationItemDAOToModel);
    };

    public deletePolicyApprovalSteps = async (params: TimeTrackingPolicyApprovalStepsParams): Promise<void> => {
        const steps = await TimeTrackingPolicyApprovalStepDAO.findAll({
            where: {
                instanceId: params.instanceId,
                ...(params.policyId !== null ? { policyId: params.policyId } : { policyId: { [Op.is]: null } }),
            },
        });

        const stepIds = steps.map((step) => step.id);
        if (stepIds.length === 0) return;

        await TimeTrackingPolicyApprovalStepResponsibleRelationDAO.destroy({ where: { approvalStepId: stepIds } });
        await TimeTrackingPolicyApprovalStepResponsibleUserDAO.destroy({ where: { approvalStepId: stepIds } });
        await TimeTrackingPolicyApprovalStepResponsibleSegmentationItemDAO.destroy({ where: { approvalStepId: stepIds } });
        await TimeTrackingPolicyApprovalStepDAO.destroy({ where: { id: stepIds } });
    };
}
