// src/server/features/reference_books/lib/contractors.drafts.ts
// Drafting logic for manager approval workflow

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

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

/**
 * Создать черновик для новой записи (менеджер)
 * Создает запись в contractors_pending с targetId: null
 */
export async function createDraft(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('Телефон обязателен');
  }

  // Создаем запись в contractors_pending с targetId: null
  const result = await db.insert(contractorsPending)
    .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,
      status: 'pending',
      targetId: null, // Новая запись, нет связи с оригиналом
      createdBy,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

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

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

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

  // Создаем заявку на согласование
  await createApprovalRequest({
    entityType: 'contractor',
    targetId: pendingEntry[0].id,
    requesterId: createdBy!,
    payload: {
      name: pendingEntry[0].name,
      category: pendingEntry[0].category,
      phone: pendingEntry[0].phone,
      action: 'create',
    },
  });

  // Уведомляем всех пользователей об изменении с полными данными (включая targetId и status)
  await notifyContractorsUpdate('contractors:created', mapPendingToContractorEntryWithMetadata(pendingEntry[0]));

  // Возвращаем pending запись в формате ContractorEntry для совместимости
  return mapPendingToContractorEntryWithMetadata(pendingEntry[0]);
}

/**
 * Создать черновик для обновления записи (менеджер)
 * Создает запись в contractors_pending с targetId: <original_id>
 */
export async function updateDraft(
  request: UpdateContractorRequest,
  existing: ContractorEntryRow
): Promise<ContractorEntryWithMetadata> {
  const { id, name, category, contractNumber, phone, email, webLink, managerName, managerPhone, managerEmail, comment, updatedBy } = request;

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

  const updates = {
    name: name || existing.name,
    category: category || existing.category,
    contractNumber: contractNumber !== undefined ? (contractNumber?.trim() || null) : existing.contractNumber,
    phone: phone || existing.phone,
    email: email !== undefined ? (email?.trim() || null) : existing.email,
    webLink: webLink !== undefined ? (webLink?.trim() || null) : existing.webLink,
    managerName: managerName !== undefined ? (managerName?.trim() || null) : existing.managerName,
    managerPhone: managerPhone !== undefined ? (managerPhone?.trim() || null) : existing.managerPhone,
    managerEmail: managerEmail !== undefined ? (managerEmail?.trim() || null) : existing.managerEmail,
    comment: comment !== undefined ? (comment?.trim() || null) : existing.comment,
  };

  const result = await db.insert(contractorsPending)
    .values({
      id: randomUUID(),
      name: updates.name.trim(),
      category: updates.category.trim(),
      contractNumber: updates.contractNumber,
      phone: updates.phone.trim(),
      email: updates.email,
      webLink: updates.webLink,
      managerName: updates.managerName,
      managerPhone: updates.managerPhone,
      managerEmail: updates.managerEmail,
      comment: updates.comment,
      status: 'pending',
      targetId: id, // Ссылка на оригинальную запись
      createdBy: updatedBy,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

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

  if (!pendingEntry[0]) {
    throw new Error('Ошибка при создании черновика на согласование');
  }

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

  // Создаем заявку на согласование
  await createApprovalRequest({
    entityType: 'contractor',
    targetId: pendingEntry[0].id,
    requesterId: updatedBy!,
    payload: {
      originalId: id,
      name: updates.name,
      category: updates.category,
      phone: updates.phone,
      action: 'update',
    },
  });

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

  // Возвращаем pending запись в формате ContractorEntry с метаданными
  return mapPendingToContractorEntryWithMetadata(pendingEntry[0]);
}

/**
 * Создать запрос на удаление (менеджер)
 * Создает запись в contractors_pending со статусом 'to_delete'
 */
export async function deleteRequest(
  id: string,
  existing: ContractorEntryRow,
  deletedBy: string
): Promise<void> {
  const result = await db.insert(contractorsPending)
    .values({
      id: randomUUID(),
      name: existing.name,
      category: existing.category,
      contractNumber: existing.contractNumber,
      phone: existing.phone,
      email: existing.email,
      webLink: existing.webLink,
      managerName: existing.managerName,
      managerPhone: existing.managerPhone,
      managerEmail: existing.managerEmail,
      comment: existing.comment,
      status: 'to_delete', // Явный статус для запроса на удаление
      targetId: id, // Ссылка на оригинальную запись для удаления
      createdBy: deletedBy,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

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

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

  logger.info(`[Contractors] Delete request created by Manager for entry: ${id}`);

  // Создаем заявку на согласование
  await createApprovalRequest({
    entityType: 'contractor',
    targetId: pendingEntry[0].id,
    requesterId: deletedBy,
    payload: {
      originalId: id,
      name: existing.name,
      category: existing.category,
      phone: existing.phone,
      action: 'delete',
    },
  });

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