// src/client/shared/api/repositories/ScheduleRepository.ts
// Schedule Repository for shift management operations with Zod validation

import { z } from 'zod';
import { BaseRepository, type RepositoryConfig } from '../BaseRepository';
import type { RequestConfig } from '../api.client';

/**
 * Shift Status Enum
 */
export const shiftStatusEnum = z.enum(['Blank', 'Work', 'Holiday', 'Unavailable']);

export type ShiftStatus = z.infer<typeof shiftStatusEnum>;

/**
 * Role at Shift Enum
 */
export const roleAtShiftEnum = z.enum(['Manager', 'Maid']);

export type RoleAtShift = z.infer<typeof roleAtShiftEnum>;

/**
 * User Role Enum
 */
export const userRoleEnum = z.enum(['ADMIN', 'MANAGER', 'MAID', 'GOD']);

export type UserRole = z.infer<typeof userRoleEnum>;

/**
 * User Response Schema
 */
export const userResponseSchema = z.object({
  id: z.string(),
  username: z.string(),
  firstName: z.string(),
  lastName: z.string(),
  fullName: z.string(),
  email: z.string().nullable().optional(),
  role: userRoleEnum.nullable(),
  isMaidAlso: z.boolean(),
});

export type UserResponse = z.infer<typeof userResponseSchema>;

/**
 * Shift Response Schema
 */
export const shiftResponseSchema = z.object({
  id: z.string(),
  date: z.string(),
  userId: z.string(),
  roleAtShift: roleAtShiftEnum,
  status: shiftStatusEnum,
  isApproved: z.boolean(),
  createdBy: z.string(),
  createdAt: z.string(),
  updatedAt: z.string(),
  archivedAt: z.string().nullable(),
});

export type ShiftResponse = z.infer<typeof shiftResponseSchema>;

/**
 * Employment Period Response Schema
 */
export const employmentPeriodResponseSchema = z.object({
  id: z.string(),
  userId: z.string(),
  startDate: z.string(),
  endDate: z.string().nullable(),
  isMaid: z.boolean(),
  createdAt: z.string(),
});

export type EmploymentPeriodResponse = z.infer<typeof employmentPeriodResponseSchema>;

/**
 * Flat schema for shifts grid data (without success wrapper)
 */
export const shiftsGridDataSchema = z.object({
  managers: z.array(userResponseSchema),
  maids: z.array(userResponseSchema),
  shifts: z.array(shiftResponseSchema),
  employmentPeriods: z.array(employmentPeriodResponseSchema),
});

export type ShiftsGridData = z.infer<typeof shiftsGridDataSchema>;

/**
 * Flat schema for pending count data (without success wrapper)
 */
export const pendingCountDataSchema = z.object({
  count: z.number(),
});

export type PendingCountData = z.infer<typeof pendingCountDataSchema>;

/**
 * Shifts Grid Response Schema
 */
export const shiftsGridResponseSchema = z.object({
  success: z.boolean(),
  data: z.object({
    managers: z.array(userResponseSchema),
    maids: z.array(userResponseSchema),
    shifts: z.array(shiftResponseSchema),
    employmentPeriods: z.array(employmentPeriodResponseSchema),
  }),
});

export type ShiftsGridResponse = z.infer<typeof shiftsGridResponseSchema>;

/**
 * Update Shift Request Schema
 */
export const updateShiftRequestSchema = z.object({
  userId: z.string(),
  date: z.string(),
  roleAtShift: roleAtShiftEnum,
  status: shiftStatusEnum,
});

export type UpdateShiftRequest = z.infer<typeof updateShiftRequestSchema>;

/**
 * Bulk Update Shifts Request Schema
 */
export const bulkUpdateShiftsRequestSchema = z.object({
  shifts: z.array(updateShiftRequestSchema),
});

export type BulkUpdateShiftsRequest = z.infer<typeof bulkUpdateShiftsRequestSchema>;

/**
 * Approve Shifts Request Schema
 */
export const approveShiftsRequestSchema = z.object({
  month: z.number().int().min(1).max(12),
  year: z.number().int().min(2000).max(2100),
});

export type ApproveShiftsRequest = z.infer<typeof approveShiftsRequestSchema>;

/**
 * Reject Shifts Request Schema
 */
export const rejectShiftsRequestSchema = z.object({
  month: z.number().int().min(1).max(12),
  year: z.number().int().min(2000).max(2100),
});

export type RejectShiftsRequest = z.infer<typeof rejectShiftsRequestSchema>;

/**
 * Success Response Schema
 */
export const successResponseSchema = z.object({
  success: z.boolean(),
  message: z.string(),
});

export type SuccessResponse = z.infer<typeof successResponseSchema>;

/**
 * Schedule Repository
 */
export class ScheduleRepository extends BaseRepository {
  protected basePath = '/schedule';

  /**
   * Получает сетку смен за месяц/год (с кэшированием)
   */
  async getShiftsGrid(month: number, year: number): Promise<ShiftsGridData> {
    const config: RequestConfig<ShiftsGridData> = {
      schema: shiftsGridDataSchema,
      params: { month, year },
    };

    return this.get<ShiftsGridData>('/shifts/grid', config);
  }

  /**
   * Получает смену по ID (с кэшированием)
   */
  async getShiftById(id: string): Promise<ShiftResponse> {
    const config: RequestConfig<ShiftResponse> = {
      schema: shiftResponseSchema,
    };

    return this.get<ShiftResponse>(`/shifts/${id}`, config);
  }

  /**
   * Массовое обновление смен
   */
  async bulkUpdateShifts(data: BulkUpdateShiftsRequest): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

    // Инвалидируем кэш после обновления
    const result = await this.post<BulkUpdateShiftsRequest, SuccessResponse>(
      '/shifts/update',
      data,
      config
    );
    this.invalidateCache();
    return result;
  }

  /**
   * Согласование смен за месяц/год
   */
  async approveShifts(month: number, year: number): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

    // Инвалидируем кэш после согласования
    const result = await this.post<ApproveShiftsRequest, SuccessResponse>(
      '/shifts/approve',
      { month, year },
      config
    );
    this.invalidateCache();
    return result;
  }

  /**
   * Отклонение смен за месяц/год
   */
  async rejectShifts(month: number, year: number): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

    // Инвалидируем кэш после отклонения
    const result = await this.post<RejectShiftsRequest, SuccessResponse>(
      '/shifts/reject',
      { month, year },
      config
    );
    this.invalidateCache();
    return result;
  }

  /**
   * Получает все смены пользователя (с кэшированием)
   */
  async getUserShifts(userId: string): Promise<ShiftResponse[]> {
    const config: RequestConfig<ShiftResponse[]> = {
      schema: z.array(shiftResponseSchema),
      params: { userId },
    };

    return this.get<ShiftResponse[]>('/shifts', config);
  }
}

/**
 * Синглтон экземпляр ScheduleRepository
 */
export const scheduleRepository = new ScheduleRepository();
