import { ApprovalUsersGatheringInterface, BasePort } from '@humand-packages/common';
import { Instance } from '../../../instances/business/models/instance';
import { UserInterface } from '../../../users/business/models/userInterface';
import TimeTrackingPoliciesFilters from '../interfaces/timeTrackingPoliciesFilters';
import TimeTrackingPoliciesOptions from '../interfaces/timeTrackingPoliciesOptions';
import { TimeTrackingPolicyApprovalStep } from '../models/policies/approvalSteps/timeTrackingPolicyApprovalStep';
import {
    TimeTrackingPolicy,
    TimeTrackingPolicyAssociation,
    TimeTrackingPolicyForCreation,
    TimeTrackingPolicyWithApprovalSteps,
} from '../models/timeTrackingPolicy';
import { TimeTrackingPolicyHourCategoryAssociation } from '../models/TimeTrackingPolicyHourCategory';
import { TimeTrackingSetting } from '../models/timeTrackingSetting';

export abstract class TimeTrackingPoliciesPort extends BasePort {
    abstract getPolicyByIdOrFail(user: UserInterface, policyId: number): Promise<TimeTrackingPolicyWithApprovalSteps>;

    abstract listPolicies(
        policiesFilters: TimeTrackingPoliciesFilters,
        options: TimeTrackingPoliciesOptions,
    ): Promise<{ count: number; rows: TimeTrackingPolicy[] }>;

    abstract listPolicyAssociations(
        policiesFilters: TimeTrackingPoliciesFilters,
        options: TimeTrackingPoliciesOptions,
    ): Promise<{ count: number; rows: TimeTrackingPolicyAssociation[] }>;

    /** Returns policy associations where toDate is null (active assignment per user). */
    abstract listActivePolicyAssociations(instanceId: number, userIds: number[]): Promise<TimeTrackingPolicyAssociation[]>;

    abstract listPolicyAssociationsEndedAt(instanceId: number, toDate: string, userIds: number[]): Promise<TimeTrackingPolicyAssociation[]>;

    abstract createPolicy(instanceId: number, policy: TimeTrackingPolicyForCreation): Promise<TimeTrackingPolicy>;
    abstract createAndAssociatePolicy(
        instanceId: number,
        policy: TimeTrackingPolicyForCreation,
        userIds: number[],
        fromDate: string,
        allUsers: boolean,
        policyHourCategories?: Array<TimeTrackingPolicyHourCategoryAssociation>,
        approvalUsers?: ApprovalUsersGatheringInterface[],
    ): Promise<TimeTrackingPolicy>;

    abstract updatePolicy(
        instance: Instance,
        user: UserInterface,
        policyId: number,
        newPolicyAttributes: Partial<TimeTrackingPolicyForCreation>,
        policyHourCategories?: Array<TimeTrackingPolicyHourCategoryAssociation>,
    ): Promise<TimeTrackingPolicy>;

    abstract associatePolicy(
        policyId: number,
        userIds: number[],
        fromDate: string,
        allUsers: boolean,
        instanceId: number,
        emitEvent?: boolean,
    ): Promise<{ usersNewlyAssigned: number[]; usersNowUnassigned: number[] }>;

    abstract eliminatePolicy(id: number, instance: Instance): Promise<void>;

    abstract getClockingInKioskEnabledUserIds(instanceId: number, userIds?: number[]): Promise<number[]>;

    abstract getUserIdsWithPolicies(instanceId: number, userIds?: number[]): Promise<number[]>;

    abstract getPoliciesOfInstance(instanceId: number): Promise<TimeTrackingPolicy[]>;

    abstract updateSettingsInPolicies(instanceId: number, settings: TimeTrackingSetting): Promise<number[]>;

    abstract listPoliciesByIds(policyIds: number[]): Promise<TimeTrackingPolicy[]>;

    abstract getApprovalSteps(instanceId: number, policyId: number | null): Promise<TimeTrackingPolicyApprovalStep[]>;

    abstract updateApprovalSteps(
        instanceId: number,
        approvalUsers: ApprovalUsersGatheringInterface[],
        policyId: number | null,
    ): Promise<TimeTrackingPolicyApprovalStep[]>;
}
