import { IHeatMap } from "../../Models/HeatMap/HeatMap.Interface";
import { IClientDocument } from "../Clients/Clients.Adapter.Mongoose";
import { ICompanyDocument } from "../Companies/Companies.Adapter.Mongoose";
import { DiscountType } from "../Discounts/Discounts.Interface";
import { TextObjectFilterResult } from "../TextObjectFilter.model";

export type FindAppointmentsParams = {
    _id?: string;
    companyId?: string;
    serviceId?: string;
    employeeId?: string;
    clientId?: string;
    start?: Date;
    dateDay?: Date;
};

export type FindAppointmentsByUserParams = {
    sessionUser: string;
};

export type FindAppointmentsByUserPaginatedParams = FindAppointmentsByUserParams & {
    page: number;
    limit: number;
};

export type FindAppointmentsByCollaboratorParams = {
    sessionUser: string;
};

export type FindAppointmentsByCollaboratorPaginatedParams = FindAppointmentsByCollaboratorParams & {
    page: number;
    limit: number;
};

export enum APPOINTMENT_NOTIFICATION_TYPE {
    "CREATION" = "creation",
    "REMINDER" = "reminder",
}

export type SendAppointmentNotificationParams = {
    appointmentId: string;
    sessionUser: string;
    type: APPOINTMENT_NOTIFICATION_TYPE;
};

export type MoveAppointmentParams = {
    id: string;
    companyId: string;
    newStart: Date;
    newEnd: Date;
    sessionUser?: string;
};

export type ChangeServiceParams = {
    id: string;
    newServiceId: string;
    newEmployeeId: string;
    sessionUser: string;
};


export type SendWapSystemNotificationParams = {
    appointmentId: string;
    systemToken: string;
};

export type HeatMapConfig = {
    companyId: string;
    serviceId: string;
    employeeId: string;
    fraction: number;
    length: number;
    heatMapDate: Date;
    start: Date;
    serviceLimit: number;
    serviceLength: number;
};

export type PaginateAppointmentsParams = FindAppointmentsParams & {
    page: number;
    limit: number;
};

export type PaginateAppointmentsResults = {
    data: IAppointment[];
    page: number;
    pages: number;
};

export type CreateAppointmentParams = {
    companyId: string;
    serviceId: string;
    employeeId: string;
    userId?: string; // for user reservations
    clientId?: string; // for collaborator reservations
    repeatId?: string; // Para ver si tiene un descuento asignado...
    start: string | Date;
    startHour?: number;
    endHour?: number;
    dateDay?: Date;
    length?: number;
    price?: number;
    comments?: string;
    validation?: boolean;
    notification?: boolean;
    sessionUser: string;
};

export type UpdateAppointmentParams = {
    id: string;
    start: string | Date;
    length: number;
    price: number;
    comments: string;
    validation?: boolean;
    notification?: boolean;
    sessionUser: string;
};

export type DeleteAppointmentParams = {
    id: string;
    validation?: boolean;
    sessionUser: string;
};

export type FindAppointmentSchedulesParams = {
    companyId: string;
    serviceId: string;
    employeeId: string;
    dateDay: string | Date;
};

export type DeleteAppointmentsByCompanyParams = {
    companyId: string;
};

export type ChangeEmployeeToOwnerParams = {
    appointmentId: string;
    companyId: string;
};

export type CountAppointmentsByMonthParams = {
    companyId: string;
    month: number;
    year: number;
};

export type SetPaymentStatusParams = {
    appointmentId: string;
    status: boolean;
    sessionUser: string;
};

export type ApplyAppointmentDiscountParams = {
    companyId: string;
    appointmentId: string;
    discountId: string;
    sessionUser: string;
};

export type DeleteAppointmentDiscountParams = {
    appointmentId: string;
    companyId: string;
    sessionUser: string;
};

export type GetAvailableDatesParams = {
    companyId: string;
    serviceId: string;
    employeeId: string;
    length: number; //Cantidad de dias para realizar el chequeo a partir de la fecha de consulta
    sessionUser: string; //El el id de un usuario cualquiera. no importa si pertenece o no a la organizacion. Es informacion publica.
};

export type GetAvailableDatesResult = {
    availableDates: Date[]; //Fechas que tienen lugar disponible.
    inRangeDates: Date[]; //Fechas que estan dentro de un periodo habilitado.
};

export interface AppointmentNotificationIntent {
    message: string;
    checkClient: IClientDocument;
    companyCheck: ICompanyDocument;
}

export interface IAppointment {
    id?: string;
    companyId: string;
    serviceId: string;
    employeeId: string;
    clientId: string;
    userId: string;

    discountId: string;
    discountType: DiscountType;
    discountValue: number;
    discountName: string;
    discountCode: string;

    start: Date;

    startHour: number;
    endHour: number;
    dateDay: Date;

    length: number;
    price: number;
    present: boolean;
    payment: boolean;
    comments: string;
    creationDate: Date;
}

export interface AppointmentEvent {
    appointmentId: string;
    startTime: number;
    endTime: number;
    title: string;
    clientId: string;
    serviceId: string;
    employeeId: string;
    avatar: string;
    color: string;
    repeatId: string;
    payment: boolean;

    discountId: string;
    discountType: DiscountType;
    discountValue: number;
    discountName: string;
    discountCode: string;
}

export interface AppointmentAdminByDateView {
    events: AppointmentEvent[];
    from: number;
    to: number;
}

export interface AppointmentEventByClient {
    id: string;
    companyId: string;
    serviceId: string;
    serviceName: string;
    serviceDescription: string;
    collaboratorId: string;
    collaboratorName: string;
    collaboratorAvatar: string;
    appointmentDate: string;
    startTime: number;
    endTime: number;
    title: string;
    clientId: string;
    clientName: string;
    avatar: string;
    color: string;
    comments: string;
    price: number;
    length: number;
    payment: boolean;

    discountId: string;
    discountType: DiscountType;
    discountValue: number;
    discountName: string;
    discountCode: string;

    clientCtaCteBalance: number;
}

export interface AppointmentAdminByClientView {
    events: AppointmentEventByClient[];
}

export interface PaginatedAppointmentEventByClientResult {
    data: AppointmentEventByClient[];
    page: number;
    pages: number;
}

export interface GetAppointmentEventParams {
    appointmentId: string;
    sessionUser: string;
}

export interface IAppointmentsAdapter {
    create(data: CreateAppointmentParams): Promise<IAppointment>;
    delete(id: string): Promise<void>;
    find(filters: FindAppointmentsParams): Promise<IAppointment[]>;
    findOne(filters: FindAppointmentsParams): Promise<IAppointment | null>;
    paginate(filters: PaginateAppointmentsParams): Promise<PaginateAppointmentsResults>;
}

export interface IAppointmentsManager {
    Appointments: IAppointmentsAdapter;
    createAppointment(data: CreateAppointmentParams): Promise<IAppointment>;
    updateAppointment(data: UpdateAppointmentParams): Promise<void>;
    moveAppointmentForce(data: MoveAppointmentParams): Promise<void>;
    changeServiceForce(data: ChangeServiceParams): Promise<void>;
    deleteAppointment(data: DeleteAppointmentParams): Promise<void>;
    buildHeatMapEmpty(config: HeatMapConfig): IHeatMap;
    getHeatMap(config: HeatMapConfig): Promise<IHeatMap>;
    updateHeatMap(config: HeatMapConfig, data: CreateAppointmentParams): Promise<void>;
    checkAvailability(config: HeatMapConfig, data: CreateAppointmentParams): Promise<boolean>;
    findAppointmentsAdminByDate(data: FindAppointmentsParams): Promise<AppointmentAdminByDateView>;
    findAppointmentsAdminByClient(data: FindAppointmentsParams): Promise<AppointmentAdminByClientView>;
    findAppointmentsByUser(data: FindAppointmentsByUserParams): Promise<AppointmentAdminByClientView>;
    findAppointmentsByCollaborator(data: FindAppointmentsByCollaboratorParams): Promise<AppointmentAdminByClientView>;
    findAppointmentsByUserPaginated(data: FindAppointmentsByUserPaginatedParams): Promise<PaginatedAppointmentEventByClientResult>;
    findAppointmentsByCollaboratorPaginated(data: FindAppointmentsByCollaboratorPaginatedParams): Promise<PaginatedAppointmentEventByClientResult>;
    getAppointmentEvent(data: GetAppointmentEventParams): Promise<AppointmentEventByClient>;
    getSchedules(data: FindAppointmentSchedulesParams): Promise<TextObjectFilterResult[]>;
    getAvailableDates(data: GetAvailableDatesParams): Promise<GetAvailableDatesResult>;
    sendWapNotification(data: SendAppointmentNotificationParams): Promise<void>;
    sendEmailNotification(data: SendAppointmentNotificationParams): Promise<void>;
    sendWapSystemNotification(data: SendWapSystemNotificationParams): Promise<void>;
    deleteAppointmentsByCompany(data: DeleteAppointmentsByCompanyParams): Promise<void>;
    changeEmployeeToOwner(data: ChangeEmployeeToOwnerParams): Promise<void>;
    countAppointmentsByMonth(data: CountAppointmentsByMonthParams): Promise<number>;
    setPaymentStatus(data: SetPaymentStatusParams): Promise<void>;
    applyDiscount(data: ApplyAppointmentDiscountParams): Promise<void>;
    deleteDiscount(data: DeleteAppointmentDiscountParams): Promise<void>;
}
