import { BaseRepositoryPort } from '@humand-packages/common';
import { LimitOffsetPagination } from '../../../../../types/listOptions';
import { HourCategory, HourCategoryForCreation, HourCategoryForUpdate } from '../../../business/models/hourCategorization';
import { CategorizedHourCategoryCount } from '../../../business/models/timeTracking/categorizedHourCategoryCount';
import {
    SavedPendingCategorizedHour,
    TimeTrackingCategorizedHourForCreation,
    TimeTrackingCategorizedHourWithCategoryData,
} from '../../../business/models/timeTracking/timeTrackingCategorizedHour';
import { TimeTrackingPolicyHourCategory, TimeTrackingHourCategoryWithAssociationData } from '../../../business/models/TimeTrackingPolicyHourCategory';
import { CategorizedHoursFilters } from '../../../business/types/hourCategorization/categorizedHoursFilters';
import { GetCategorizedHoursVC } from '../../../presentation/validationClasses/hourCategorization/getCategorizedHoursVC';
import { UpdateCategorizedHourVC } from '../../../presentation/validationClasses/hourCategorization/updateCategorizedHourVC';

export abstract class TimeTrackingHourCategorizationRepositoryPort extends BaseRepositoryPort {
    abstract listHourCategories(
        instanceId: number,
        pagination: LimitOffsetPagination,
        targetDateString?: string,
        search?: string,
    ): Promise<{ count: number; rows: HourCategory[] }>;

    abstract getHourCategory(instanceId: number, id: number, options?: { includeDeleted?: boolean }): Promise<HourCategory>;
    abstract createHourCategory(instanceId: number, hourCategory: HourCategoryForCreation): Promise<HourCategory>;
    abstract updateHourCategory(instanceId: number, id: number, hourCategory: HourCategoryForUpdate): Promise<HourCategory>;
    abstract deleteHourCategory(instanceId: number, id: number): Promise<void>;
    abstract listHourCategoriesForPolicy(
        instanceId: number,
        policyId: number,
        pagination: LimitOffsetPagination,
        search?: string,
    ): Promise<{ count: number; rows: Array<TimeTrackingPolicyHourCategory> }>;

    abstract saveCategorizedHours(
        instanceId: number,
        categorizedHours: Map<string, TimeTrackingCategorizedHourForCreation[]>,
    ): Promise<SavedPendingCategorizedHour[]>;

    abstract getApprovedCategorizedHoursMap(
        instanceId: number,
        userIds: number[],
        dateStrings: string[],
    ): Promise<Map<string, TimeTrackingCategorizedHourWithCategoryData[]>>;

    abstract getApprovedCategorizedHours(
        instanceId: number,
        userIds: number[],
        dateStrings: string[],
    ): Promise<TimeTrackingCategorizedHourWithCategoryData[]>;

    /**
     * Returns every stored categorized hour for a single (user, date) regardless of status,
     * including PENDING, REJECTED and admin-overridden rows. Used by the explain endpoint
     * so the UI can show drift between the recomputed AST and what is persisted.
     */
    abstract getCategorizedHoursForUserDate(
        instanceId: number,
        userId: number,
        dateString: string,
    ): Promise<TimeTrackingCategorizedHourWithCategoryData[]>;

    abstract getDistinctApprovedCategoryIds(instanceId: number, userIds: number[], fromDate: string, toDate: string): Promise<Set<number>>;

    abstract getPolicyHourCategoriesForPolicyIds(
        policyIds: number[],
        instanceId: number,
        targetDate?: string,
    ): Promise<Array<TimeTrackingHourCategoryWithAssociationData>>;

    abstract getPolicyHourCategoriesByHourCategoryIds(
        instanceId: number,
        hourCategoryIds: number[],
        targetDate?: string,
    ): Promise<Array<TimeTrackingHourCategoryWithAssociationData>>;

    abstract getPendingCategorizedHoursAmount(instanceId: number, loggedUserId: number): Promise<number>;
    abstract listCategorizedHours(
        instanceId: number,
        pagination: LimitOffsetPagination,
        filters: GetCategorizedHoursVC,
        loggedUserId: number,
        hasManageCapability: boolean,
        searchedUserIds?: number[],
        approverCategorizedHourIds?: string[],
    ): Promise<{ count: number; rows: TimeTrackingCategorizedHourWithCategoryData[] }>;

    abstract getCategorizedHour(instanceId: number, categorizedHourId: string): Promise<TimeTrackingCategorizedHourWithCategoryData | null>;

    abstract updateCategorizedHour(
        instanceId: number,
        categorizedHourId: string,
        params: UpdateCategorizedHourVC,
    ): Promise<TimeTrackingCategorizedHourWithCategoryData>;

    abstract listCategorizedHourIdsByFilters(input: {
        instanceId: number;
        filters: CategorizedHoursFilters;
        loggedUserId: number;
        hasManageCapability: boolean;
        searchedUserIds?: number[];
    }): Promise<string[]>;

    abstract countCategorizedHoursByCategory(input: {
        instanceId: number;
        filters: CategorizedHoursFilters;
        loggedUserId: number;
        hasManageCapability: boolean;
        searchedUserIds?: number[];
        approverCategorizedHourIds?: string[];
    }): Promise<CategorizedHourCategoryCount[]>;
}
