// src/client/shared/api/repositories/InventoryRepository.ts
// Inventory Repository for inventory management operations with Zod validation

import { z } from 'zod';
import { BaseRepository, type RepositoryConfig } from '../BaseRepository';
import type { RequestConfig } from '../api.client';
import type { InventoryEntry } from '@shared/contracts/inventory';

/**
 * Категории инвентаря
 */
export const inventoryCategorySchema = z.enum([
  'tools',        // Инструменты
  'consumables',  // Расходники
  'linen',        // Белье
  'tableware',    // Посуда
  'equipment',    // Оборудование
  'other',        // Другое
]);

export type InventoryCategory = z.infer<typeof inventoryCategorySchema>;

/**
 * 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);

/**
 * Inventory Response (DTO) - синхронизировано с бэкендом
 * FIX: Added status, targetId, createdBy, creatorName, reviewedBy, reviewedAt, rejectionReason, isApproved
 */
export const inventoryResponseSchema = z.object({
  id: z.string(),
  name: z.string(),
  category: z.string(),
  quantity: z.string(),
  unit: z.string().nullable(),
  location: z.string(),
  comment: z.string().nullable(),
  weightPerUnit: z.string().nullable(),
  manufacturer: z.string().nullable(),
  model: z.string().nullable(),
  serialNumber: z.string().nullable(),
  orderingLink: z.string().nullable(),
  articleNumber: z.string().nullable(),
  isApproved: z.boolean(),
  status: z.enum(['pending', 'approved', 'rejected', 'to_delete']).optional(),
  targetId: z.string().nullable(),
  createdBy: z.string().nullable(),
  creatorName: z.string().nullable(),
  reviewedBy: z.string().nullable(),
  reviewedAt: z.string().nullable(),
  rejectionReason: z.string().nullable(),
  createdAt: z.string(),
  updatedAt: z.string(),
  archivedAt: z.string().nullable(),
});

export type InventoryResponse = z.infer<typeof inventoryResponseSchema>;

// Inventory pending entry response schema
export const inventoryPendingEntryResponseSchema = z.object({
  id: z.string(),
  name: z.string(),
  category: z.string(),
  quantity: z.string(),
  unit: z.string().nullable(),
  location: z.string(),
  comment: z.string().nullable(),
  weightPerUnit: z.string().nullable(),
  manufacturer: z.string().nullable(),
  model: z.string().nullable(),
  serialNumber: z.string().nullable(),
  orderingLink: z.string().nullable(),
  articleNumber: z.string().nullable(),
  status: z.enum(['pending', 'approved', 'rejected', 'to_delete']),
  targetId: z.string().nullable(),
  createdBy: z.string().nullable(),
  creatorName: z.string().nullable(),
  reviewedBy: z.string().nullable(),
  reviewedAt: z.string().nullable(),
  rejectionReason: z.string().nullable(),
  createdAt: z.string(),
  updatedAt: z.string(),
});

export type InventoryPendingEntryResponse = z.infer<typeof inventoryPendingEntryResponseSchema>;

// Inventory list response schema
export const inventoryListResponseSchema = z.array(inventoryResponseSchema);

// Create Inventory Request
export const createInventoryRequestSchema = z.object({
  name: z.string().min(1, 'Название обязательно'),
  category: inventoryCategorySchema,
  quantity: z.number().min(0, 'Количество не может быть отрицательным'),
  unit: z.string().optional(),
  location: z.string().min(1, 'Локация обязательна'),
  comment: emptyToNull,
  weightPerUnit: z.number().min(0).optional(),
  manufacturer: z.string().optional(),
  model: z.string().optional(),
  serialNumber: z.string().optional(),
  orderingLink: z.string().optional(),
  articleNumber: z.string().optional(),
});

export type CreateInventoryRequest = z.infer<typeof createInventoryRequestSchema>;

// Update Inventory Request
export const updateInventoryRequestSchema = z.object({
  name: z.string().min(1).optional(),
  category: inventoryCategorySchema.optional(),
  quantity: z.number().min(0).optional(),
  unit: z.string().optional(),
  location: z.string().min(1).optional(),
  comment: emptyToNull,
  weightPerUnit: z.number().min(0).optional(),
  manufacturer: z.string().optional(),
  model: z.string().optional(),
  serialNumber: z.string().optional(),
  orderingLink: z.string().optional(),
  articleNumber: z.string().optional(),
});

export type UpdateInventoryRequest = z.infer<typeof updateInventoryRequestSchema>;

// 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>;

/**
 * Inventory Repository
 */
export class InventoryRepository extends BaseRepository {
  protected basePath = '/inventory';

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

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

  /**
   * Получает инвентарь по категории (с кэшированием)
   */
  async getByCategory(category: InventoryCategory): Promise<InventoryResponse[]> {
    const config: RequestConfig<InventoryResponse[]> = {
      schema: inventoryListResponseSchema,
      params: { category },
    };

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

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

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

  /**
   * Создает новую запись инвентаря
   */
  async create(data: CreateInventoryRequest): Promise<InventoryResponse> {
    const config: RequestConfig<InventoryResponse> = {
      schema: inventoryResponseSchema,
    };

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

  /**
   * Обновляет запись инвентаря
   */
  async update(id: string, data: UpdateInventoryRequest): Promise<InventoryResponse> {
    const config: RequestConfig<InventoryResponse> = {
      schema: inventoryResponseSchema,
    };

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

  /**
   * Архивирует запись инвентаря
   */
  async archive(id: string): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

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

  /**
   * Получает все pending записи инвентаря
   */
  async getPending(): Promise<InventoryPendingEntryResponse[]> {
    const config: RequestConfig<InventoryPendingEntryResponse[]> = {
      schema: z.array(inventoryPendingEntryResponseSchema),
    };

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

  /**
   * Одобряет запись инвентаря
   */
  async approve(id: string): Promise<InventoryResponse> {
    const config: RequestConfig<InventoryResponse> = {
      schema: inventoryResponseSchema,
    };

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

  /**
   * Отклоняет запись инвентаря
   */
  async reject(id: string, reason: string): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

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

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