// src/client/shared/api/repositories/EmployeeRepository.ts
// Employee Repository for personnel management operations with Zod validation

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

/**
 * Схемы для валидации запросов/ответов (синхронизированы с бэкендом)
 */

// Phone validation: 10-11 digits
const phoneSchema = z.string().regex(/^\d{10,11}$/, 'Phone must be 10-11 digits');

// Optional phone schema for updates
const phoneSchemaOptional = z.union([
  z.string().regex(/^\d{10,11}$/, 'Phone must be 10-11 digits'),
  z.null(),
]).optional();

// Email validation (optional - can be empty string or null)
const emailSchema = z.union([
  z.string().email('Invalid email format'),
  z.literal(''),
  z.null(),
]).optional().transform(v => v === '' ? null : v);

// Helper to transform empty strings and undefined to null
const emptyToNull = z.union([
  z.string().optional(),
  z.literal(''),
  z.null(),
]).transform(val => val === '' || val === undefined || val === null ? null : val);

// Helper to transform empty strings and undefined to null for dates
const emptyDateToNull = z.union([
  z.string().optional(),
  z.literal(''),
  z.null(),
]).transform(val => {
  if (val === '' || val === undefined || val === null) return null;
  // Validate it's a valid date string
  const date = new Date(val);
  if (isNaN(date.getTime())) return null;
  return val;
});

// Maid period schema for managing maid role periods
export const maidPeriodSchema = z.object({
  id: z.string().optional(), // Optional for new periods
  startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Invalid date format, expected YYYY-MM-DD'),
  endDate: z.union([
    z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Invalid date format, expected YYYY-MM-DD'),
    z.literal(''),
    z.null(),
  ]).optional().transform(val => val === '' || val === null ? null : val),
  _deleted: z.boolean().optional(), // Flag to mark period for deletion
});

// Maid period response schema
export const maidPeriodResponseSchema = z.object({
  id: z.string(),
  startDate: z.string(), // YYYY-MM-DD format
  endDate: z.union([
    z.string(),
    z.literal(''),
    z.null(),
  ]).transform(val => val === '' || val === null ? null : val), // YYYY-MM-DD format or null
});

/**
 * Employee Response (DTO) - КРИТИЧНО: passwordHash исключен
 * .passthrough() добавлен для временного отключения строгой валидации (debug mode)
 */
export const employeeResponseSchema = z.object({
  id: z.string(),
  fullName: z.string(),
  position: z.string(),
  phone: z.string().nullable(),
  email: z.string().nullable(),
  birthDate: z.string().nullable(),
  address: z.string().nullable(),
  notes: z.string().nullable(),
  isFired: z.boolean(),
  firedReason: z.string().nullable(),
  username: z.string().nullable(),
  role: z.string().nullable(),
  isMentionable: z.boolean().optional(),
  isMaidAlso: z.boolean(), // Computed field - true if employee has active maid period today
  maidPeriods: z.array(maidPeriodResponseSchema), // Array of all maid periods
  createdAt: z.string(),
  updatedAt: z.string(),
  archivedAt: z.string().nullable(),
}); // TEMPORARY: Allow extra fields from backend for debugging

export type EmployeeResponse = z.infer<typeof employeeResponseSchema>;

// Employees list response schema
export const employeesListResponseSchema = z.array(employeeResponseSchema);

// Create Employee Request
export const createEmployeeRequestSchema = z.object({
  fullName: z.string().min(1, 'Full name is required'),
  position: z.string().min(1, 'Position is required'),
  phone: phoneSchema,
  email: emailSchema,
  birthDate: emptyDateToNull,
  address: emptyToNull,
  notes: emptyToNull,
  hireDate: z.string().datetime().optional(), // Дата приёма (ISO datetime string)
  createUser: z.boolean().optional(),
  username: z.string().optional(), // Optional - will be auto-generated for MAID role
  password: z.string().min(6, 'Password must be at least 6 characters').optional(),
  role: z.enum(['ADMIN', 'MANAGER', 'MAID']).default('MANAGER').optional(),
  maidPeriods: z.array(maidPeriodSchema).optional(),
});

export type CreateEmployeeRequest = z.infer<typeof createEmployeeRequestSchema>;

// Update Employee Request
export const updateEmployeeRequestSchema = z.object({
  fullName: z.string().min(1, 'Full name is required').optional(),
  position: z.string().min(1, 'Position is required').optional(),
  phone: phoneSchemaOptional,
  email: emailSchema,
  birthDate: emptyDateToNull,
  address: emptyToNull,
  notes: emptyToNull,
  hireDate: z.string().datetime().optional(), // Дата приёма (ISO datetime string)
  password: z.string().min(6, 'Password must be at least 6 characters').optional().or(z.literal('')),
  // User creation fields for "promote to user" functionality
  createUser: z.boolean().optional(),
  username: z.string().optional(),
  role: z.enum(['ADMIN', 'MANAGER', 'MAID']).optional(),
  // Field for unified handling of firing/return reason
  firedReason: emptyToNull,
  isFired: z.boolean().optional(),
  archivedAt: z.string().datetime().nullable().optional(), // Termination date (ISO datetime string)
  // Maid periods array for managing maid role history
  maidPeriods: z.array(maidPeriodSchema).optional(),
});

export type UpdateEmployeeRequest = z.infer<typeof updateEmployeeRequestSchema>;

// Fire employee request
export const fireEmployeeRequestSchema = z.object({
  firedReason: z.string().min(1, 'Firing reason is required'),
  firedAt: z.string().datetime().optional(),
});

export type FireEmployeeRequest = z.infer<typeof fireEmployeeRequestSchema>;

// Rehire employee request
export const rehireEmployeeRequestSchema = z.object({
  returnReason: z.string().min(3, 'Причина восстановления слишком коротка'),
  rehireDate: z.string().datetime().optional(), // Дата восстановления (ISO datetime string)
  maidPeriods: z.array(maidPeriodSchema).optional(), // Optional maid periods for rehire
});

export type RehireEmployeeRequest = z.infer<typeof rehireEmployeeRequestSchema>;

// Check username availability request schema
export const checkUsernameRequestSchema = z.object({
  username: z.string().min(1, 'Username is required'),
});

export type CheckUsernameRequest = z.infer<typeof checkUsernameRequestSchema>;

// Check username availability response schema
export const checkUsernameResponseSchema = z.object({
  available: z.boolean(),
});

export type CheckUsernameResponse = z.infer<typeof checkUsernameResponseSchema>;

// Simple success response schema for mutation operations
export const successResponseSchema = z.object({
  success: z.boolean(),
  message: z.string(),
});

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

/**
 * Employee Repository
 */
export class EmployeeRepository extends BaseRepository {
  protected basePath = '/employees';

  /**
   * Получает всех сотрудников (с кэшированием)
   */
  async getAll(): Promise<EmployeeResponse[]> {
    const config: RequestConfig<EmployeeResponse[]> = {
      schema: employeesListResponseSchema,
    };

    return this.get<EmployeeResponse[]>('', config);
  }

  /**
   * Получает сотрудников по статусу (с кэшированием)
   */
  async getByStatus(status: 'active' | 'fired'): Promise<EmployeeResponse[]> {
    const isFiredParam = status === 'fired';
    const config: RequestConfig<EmployeeResponse[]> = {
      schema: employeesListResponseSchema,
      params: { isFired: isFiredParam },
    };

    return this.get<EmployeeResponse[]>('', config);
  }

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

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

  /**
   * Проверяет доступность имени пользователя (без кэширования)
   */
  async checkUsername(username: string): Promise<CheckUsernameResponse> {
    const config: RequestConfig<CheckUsernameResponse> = {
      schema: checkUsernameResponseSchema,
    };

    return this.getNoCache<CheckUsernameResponse>(`/check-username?username=${encodeURIComponent(username)}`, config);
  }

  /**
   * Создает нового сотрудника
   */
  async create(data: CreateEmployeeRequest): Promise<EmployeeResponse> {
    const config: RequestConfig<EmployeeResponse> = {
      schema: employeeResponseSchema,
    };

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

  /**
   * Обновляет сотрудника
   */
  async update(id: string, data: UpdateEmployeeRequest): Promise<EmployeeResponse> {
    const config: RequestConfig<EmployeeResponse> = {
      schema: employeeResponseSchema,
    };

    // Инвалидируем кэш после обновления
    const result = await this.put<UpdateEmployeeRequest, EmployeeResponse>(`/${id}`, data, config);
    this.invalidateCache();
    return result;
  }

  /**
   * Увольняет сотрудника
   */
  async fire(id: string, data: FireEmployeeRequest): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

    // Инвалидируем кэш после увольнения
    const result = await this.post<FireEmployeeRequest, SuccessResponse>(`/${id}/fire`, data, config);
    this.invalidateCache();
    return result;
  }

  /**
   * Восстанавливает сотрудника
   */
  async rehire(id: string, data: RehireEmployeeRequest): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

    // Инвалидируем кэш после восстановления
    const result = await this.post<RehireEmployeeRequest, SuccessResponse>(`/${id}/rehire`, data, config);
    this.invalidateCache();
    return result;
  }

  /**
   * Восстанавливает сотрудника (restore endpoint)
   */
  async restore(id: string): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

    // Инвалидируем кэш после восстановления
    const result = await this.post<{}, SuccessResponse>(`/${id}/restore`, {}, config);
    this.invalidateCache();
    return result;
  }

  /**
   * Удаляет сотрудника
   */
  async deleteEmployee(id: string): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

    // Инвалидируем кэш после удаления
    const result = await super.delete<SuccessResponse>(`/${id}`, config);
    this.invalidateCache();
    return result;
  }

  /**
   * Экспортирует сотрудников в CSV (без кэширования)
   */
  async export(): Promise<Blob> {
    const fullEndpoint = `${this.basePath}/export`;
    const response = await fetch(fullEndpoint, {
      method: 'GET',
      credentials: 'include',
    });

    if (!response.ok) {
      throw new Error('Failed to export employees');
    }

    return response.blob();
  }
}

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