// src/client/shared/api/repositories/ContractorsRepository.ts
// Repository for contractors API calls with caching and error handling

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

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

/**
 * Contractor Response (DTO) - синхронизировано с бэкендом
 * Поддерживает как одобренные записи, так и записи на согласовании
 */
export const contractorResponseSchema = z.object({
  id: z.string(),
  name: z.string(),
  category: z.string(),
  contractNumber: z.string().nullable(),
  phone: z.string(),
  email: z.string().nullable(),
  webLink: z.string().nullable(),
  managerName: z.string().nullable(),
  managerPhone: z.string().nullable(),
  managerEmail: z.string().nullable(),
  comment: 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 ContractorResponse = z.infer<typeof contractorResponseSchema>;

// Contractor list response schema
export const contractorListResponseSchema = z.array(contractorResponseSchema);

/**
 * Contractor Pending Entry Response (DTO) - для записей на согласовании
 */
export const contractorPendingEntrySchema = z.object({
  id: z.string(),
  name: z.string(),
  category: z.string(),
  contractNumber: z.string().nullable(),
  phone: z.string(),
  email: z.string().nullable(),
  webLink: z.string().nullable(),
  managerName: z.string().nullable(),
  managerPhone: z.string().nullable(),
  managerEmail: z.string().nullable(),
  comment: 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 ContractorPendingEntryResponse = z.infer<typeof contractorPendingEntrySchema>;

// Contractor pending list response schema
export const contractorPendingListResponseSchema = z.array(contractorPendingEntrySchema);

// Create Contractor Request
export const createContractorRequestSchema = z.object({
  name: z.string().min(1, 'Название обязательно'),
  category: z.string().min(1, 'Категория обязательна'),
  contractNumber: z.string().nullable(),
  phone: z.string().min(1, 'Телефон обязателен'),
  email: z.string().nullable(),
  webLink: z.string().nullable(),
  managerName: z.string().nullable(),
  managerPhone: z.string().nullable(),
  managerEmail: z.string().nullable(),
  comment: emptyToNull,
}).transform((data) => ({
  ...data,
  // Transform empty strings to null for optional fields
  contractNumber: data.contractNumber?.trim() || null,
  email: data.email?.trim() || null,
  webLink: data.webLink?.trim() || null,
  managerName: data.managerName?.trim() || null,
  managerPhone: data.managerPhone?.trim() || null,
  managerEmail: data.managerEmail?.trim() || null,
}));

export type CreateContractorRequest = z.infer<typeof createContractorRequestSchema>;

// Update Contractor Request
export const updateContractorRequestSchema = z.object({
  name: z.string().min(1).optional(),
  category: z.string().min(1).optional(),
  contractNumber: z.string().nullable(),
  phone: z.string().min(1).optional(),
  email: z.string().nullable(),
  webLink: z.string().nullable(),
  managerName: z.string().nullable(),
  managerPhone: z.string().nullable(),
  managerEmail: z.string().nullable(),
  comment: emptyToNull,
}).transform((data) => ({
  ...data,
  // Transform empty strings to null for optional fields
  contractNumber: data.contractNumber?.trim() || null,
  email: data.email?.trim() || null,
  webLink: data.webLink?.trim() || null,
  managerName: data.managerName?.trim() || null,
  managerPhone: data.managerPhone?.trim() || null,
  managerEmail: data.managerEmail?.trim() || null,
}));

export type UpdateContractorRequest = z.infer<typeof updateContractorRequestSchema>;

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

/**
 * Contractors Repository
 * Handles all API calls for contractors management
 */
export class ContractorsRepository extends BaseRepository {
  protected basePath = '/contractors';

  /**
   * Get all contractors (with caching)
   * Бэкенд сам определит логику слияния для всех записей
   */
  async getAll(archived?: boolean, status?: 'all' | 'pending' | 'approved'): Promise<ContractorResponse[]> {
    const params: Record<string, string> = {};

    // Добавляем параметры только если они явно переданы
    if (archived !== undefined) {
      params.archived = archived.toString();
    }
    if (status !== undefined) {
      params.status = status;
    }

    const config: RequestConfig<ContractorResponse[]> = {
      schema: contractorListResponseSchema,
      params: Object.keys(params).length > 0 ? params : undefined,
    };

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

  /**
   * Get contractor by ID (with caching)
   */
  async getById(id: string): Promise<ContractorResponse> {
    const config: RequestConfig<ContractorResponse> = {
      schema: contractorResponseSchema,
    };

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

  /**
   * Create new contractor
   */
  async create(data: CreateContractorRequest): Promise<ContractorResponse> {
    const config: RequestConfig<ContractorResponse> = {
      schema: contractorResponseSchema,
    };

    // Invalidate cache after creation
    const result = await this.post<CreateContractorRequest, ContractorResponse>('', data, config);
    this.invalidateCache();
    return result;
  }

  /**
   * Update contractor
   */
  async update(id: string, data: UpdateContractorRequest): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

    // Invalidate cache after update
    const result = await this.put<UpdateContractorRequest, SuccessResponse>(`/${id}`, data, config);
    this.invalidateCache();
    return result;
  }

  /**
   * Archive contractor (soft delete)
   */
  async archive(id: string): Promise<SuccessResponse> {
    const config: RequestConfig<SuccessResponse> = {
      schema: successResponseSchema,
    };

    // Invalidate cache after deletion
    const result = await super.delete<SuccessResponse>(`/${id}`, config);
    this.invalidateCache();
    return result;
  }

  /**
   * Get pending (unapproved) entries
   */
  async getPending(): Promise<ContractorPendingEntryResponse[]> {
    const config: RequestConfig<ContractorPendingEntryResponse[]> = {
      schema: contractorPendingListResponseSchema,
    };

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

  /**
   * Approve single pending entry (ADMIN only)
   */
  async approveEntry(id: string): Promise<{ success: boolean }> {
    const config: RequestConfig<{ success: boolean }> = {
      schema: z.object({ success: z.boolean() }),
    };

    // Invalidate cache on approve
    const result = await this.post<void, { success: boolean }>(`/approve/${id}`, undefined, config);
    this.invalidateCache();
    return result;
  }

  /**
   * Reject single pending entry (ADMIN only)
   */
  async rejectEntry(id: string): Promise<{ success: boolean }> {
    const config: RequestConfig<{ success: boolean }> = {
      schema: z.object({ success: z.boolean() }),
    };

    // Invalidate cache on reject
    const result = await this.post<void, { success: boolean }>(`/reject/${id}`, undefined, config);
    this.invalidateCache();
    return result;
  }
}

/**
 * Singleton instance of ContractorsRepository
 */
export const contractorsRepository = new ContractorsRepository();
