// src/server/features/reference_books/lib/contractors.core.ts
// Core admin actions for direct database operations

import { db } from '../../../shared/db/client';
import { contractors, contractorsPending } from '../db/contractors.table';
import { approvalRequests } from '../../approval/db/approval_requests.table';
import { eq, and, isNull } from 'drizzle-orm';
import { randomUUID } from 'node:crypto';
import { logger } from '../../../shared/lib/logger';
import { notifyContractorsUpdate } from './contractors.notifications';
import { mapToContractorEntry } from './contractors.mapper';
import type { ContractorEntryWithMetadata, CreateContractorRequestWithAdmin, UpdateContractorRequestWithAdmin, CreateContractorRequest, UpdateContractorRequest } from '../contractors.schema';

// Type for contractor entry
type ContractorEntry = typeof contractors.$inferSelect;

/**
 * Прямое создание записи в таблице contractors (админ)
 */
export async function executeCreate(request: CreateContractorRequest): Promise<ContractorEntryWithMetadata> {
  const { name, category, contractNumber, phone, email, webLink, managerName, managerPhone, managerEmail, comment, createdBy } = request;

  // Валидация обязательных полей
  if (!name || name.trim().length === 0) {
    throw new Error('Название обязательно');
  }
  if (!category || category.trim().length === 0) {
    throw new Error('Категория обязательна');
  }
  if (!phone || phone.trim().length === 0) {
    throw new Error('Телефон обязателен');
  }

  const result = await db.insert(contractors)
    .values({
      id: randomUUID(),
      name: name.trim(),
      category: category.trim(),
      contractNumber: contractNumber?.trim() || null,
      phone: phone.trim(),
      email: email?.trim() || null,
      webLink: webLink?.trim() || null,
      managerName: managerName?.trim() || null,
      managerPhone: managerPhone?.trim() || null,
      managerEmail: managerEmail?.trim() || null,
      comment: comment?.trim() || null,
      isApproved: true,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

  const entry = await db.select()
    .from(contractors)
    .where(eq(contractors.id, result[0].id))
    .limit(1);

  if (!entry[0]) {
    throw new Error('Ошибка при создании записи');
  }

  logger.info(`[Contractors] Entry created by Admin: ${name}`);

  // Уведомляем всех пользователей об изменении с полными данными
  await notifyContractorsUpdate('contractors:created', mapToContractorEntry(entry[0]));

  return mapToContractorEntry(entry[0]);
}

/**
 * Прямое обновление записи в таблице contractors (админ)
 */
export async function executeUpdate(
  id: string,
  request: Omit<UpdateContractorRequest, 'id'>
): Promise<ContractorEntryWithMetadata> {
  const { name, category, contractNumber, phone, email, webLink, managerName, managerPhone, managerEmail, comment } = request;

  const updates: any = {
    isApproved: true,
    updatedAt: new Date(),
  };

  if (name !== undefined) updates.name = name.trim();
  if (category !== undefined) updates.category = category.trim();
  if (contractNumber !== undefined) updates.contractNumber = contractNumber?.trim() || null;
  if (phone !== undefined) updates.phone = phone.trim();
  if (email !== undefined) updates.email = email?.trim() || null;
  if (webLink !== undefined) updates.webLink = webLink?.trim() || null;
  if (managerName !== undefined) updates.managerName = managerName?.trim() || null;
  if (managerPhone !== undefined) updates.managerPhone = managerPhone?.trim() || null;
  if (managerEmail !== undefined) updates.managerEmail = managerEmail?.trim() || null;
  if (comment !== undefined) updates.comment = comment?.trim() || null;

  await db.update(contractors)
    .set(updates)
    .where(eq(contractors.id, id));

  logger.info(`[Contractors] Entry updated by Admin: ${id}`);

  const updated = await db.select()
    .from(contractors)
    .where(eq(contractors.id, id))
    .limit(1);

  // Уведомляем об изменении с полными данными
  await notifyContractorsUpdate('contractors:updated', mapToContractorEntry(updated[0]));

  return mapToContractorEntry(updated[0]);
}

/**
 * Архивация записи в таблице contractors (админ)
 * Каскадно удаляет все связанные черновики и заявки
 */
export async function executeDelete(id: string): Promise<void> {
  // Каскадное удаление всех связанных черновиков
  await db.delete(contractorsPending)
    .where(eq(contractorsPending.targetId, id));

  // Архивация оригинальной записи (soft delete)
  await db.update(contractors)
    .set({
      archivedAt: new Date(),
      updatedAt: new Date(),
    })
    .where(eq(contractors.id, id));

  // Удаляем связанные заявки из approvalRequests
  await db.delete(approvalRequests)
    .where(and(
      eq(approvalRequests.entityType, 'contractor'),
      eq(approvalRequests.targetId, id)
    ));

  logger.info(`[Contractors] Entry archived by Admin: ${id}`);

  // Уведомляем об удалении с action: 'remove' для однозначного определения на фронтенде
  await notifyContractorsUpdate('contractors:deleted', { id, action: 'remove' });
}

/**
 * Автоматическое согласование черновика при редактировании админом
 * Создает или обновляет запись в contractors и удаляет черновик
 */
export async function autoApproveDraft(
  pendingId: string,
  pendingEntry: typeof contractorsPending.$inferSelect,
  updatedBy: string,
  updates: any
): Promise<ContractorEntryWithMetadata> {
  return await db.transaction(async (tx) => {
    let finalId: string;

    // Если есть targetId - обновляем оригинальную запись в contractors
    if (pendingEntry.targetId) {
      await tx.update(contractors)
        .set({
          ...updates,
          isApproved: true,
        })
        .where(eq(contractors.id, pendingEntry.targetId));

      finalId = pendingEntry.targetId;
      logger.info(`[Contractors] Admin auto-approved update for pending entry: ${pendingId} -> ${finalId}`);
    } else {
      // Если нет targetId - создаем новую запись в contractors
      const result = await tx.insert(contractors)
        .values({
          id: randomUUID(),
          name: updates.name,
          category: updates.category,
          contractNumber: updates.contractNumber,
          phone: updates.phone,
          email: updates.email,
          webLink: updates.webLink,
          managerName: updates.managerName,
          managerPhone: updates.managerPhone,
          managerEmail: updates.managerEmail,
          comment: updates.comment,
          isApproved: true,
          createdAt: new Date(),
          updatedAt: updates.updatedAt,
        })
        .$returningId();

      finalId = result[0].id;
      logger.info(`[Contractors] Admin auto-approved new entry from pending: ${pendingId} -> ${finalId}`);
    }

    // Удаляем запись из contractors_pending
    await tx.delete(contractorsPending)
      .where(eq(contractorsPending.id, pendingId));

    // Удаляем соответствующую заявку из approvalRequests
    await tx.delete(approvalRequests)
      .where(and(
        eq(approvalRequests.entityType, 'contractor'),
        eq(approvalRequests.targetId, pendingId)
      ));

    // Получаем финальную запись из contractors для уведомления
    const finalEntry = await tx.select()
      .from(contractors)
      .where(eq(contractors.id, finalId))
      .limit(1);

    // Эмитим событие для мгновенного обновления на фронтенде с полными данными
    await notifyContractorsUpdate('contractors:updated', mapToContractorEntry(finalEntry[0]), tx);

    return mapToContractorEntry(finalEntry[0]);
  });
}

/**
 * Обновление черновика (без согласования)
 */
export async function updatePendingDraft(
  id: string,
  updates: any
): Promise<ContractorEntryWithMetadata> {
  await db.update(contractorsPending)
    .set(updates)
    .where(eq(contractorsPending.id, id));

  logger.info(`[Contractors] Pending entry updated: ${id} by Manager`);

  const updated = await db.select()
    .from(contractorsPending)
    .where(eq(contractorsPending.id, id))
    .limit(1);

  // Уведомляем об изменении с полными данными (включая targetId и статус)
  const { mapPendingToContractorEntryWithMetadata } = await import('./contractors.mapper');
  await notifyContractorsUpdate('contractors:updated', mapPendingToContractorEntryWithMetadata(updated[0]));

  return mapPendingToContractorEntryWithMetadata(updated[0]);
}

/**
 * Удаление черновика (чистое удаление)
 */
export async function deletePendingDraft(id: string): Promise<void> {
  // Удаляем запись из contractors_pending
  await db.delete(contractorsPending)
    .where(eq(contractorsPending.id, id));

  // Удаляем связанную заявку из approvalRequests
  await db.delete(approvalRequests)
    .where(and(
      eq(approvalRequests.entityType, 'contractor'),
      eq(approvalRequests.targetId, id)
    ));

  logger.info(`[Contractors] Pending entry deleted (clean delete): ${id}`);

  // Уведомляем об удалении с action: 'remove' для однозначного определения на фронтенде
  await notifyContractorsUpdate('contractors:deleted', { id, action: 'remove' });
}
