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

import { db } from '../../../shared/db/client';
import { blacklistPending, blacklist } from '../db/blacklist.table';
import { eq, and, isNull } from 'drizzle-orm';
import { randomUUID } from 'node:crypto';
import { logger } from '../../../shared/lib/logger';
import { notifyBlacklistUpdate } from './blacklist.notifications';
import { createApprovalRequest } from '../../approval/approval.service';
import { mapPendingToBlacklistEntryWithMetadata } from './blacklist.mapper';
import type { BlacklistEntryWithMetadata, CreateBlacklistRequest, UpdateBlacklistRequest } from '../blacklist.schema';

// Type for existing blacklist entry
type BlacklistEntryRow = typeof blacklist.$inferSelect;

/**
 * Создать черновик для новой записи (менеджер)
 * Создает запись в blacklist_pending с targetId: null
 */
export async function createDraft(request: CreateBlacklistRequest): Promise<BlacklistEntryWithMetadata> {
  const { name, phone, bookingEngineCheck, comment, createdBy } = request;

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

  // Создаем запись в blacklist_pending с targetId: null
  const result = await db.insert(blacklistPending)
    .values({
      id: randomUUID(),
      name: name.trim(),
      phone: phone.trim(),
      bookingEngineCheck,
      comment: comment?.trim() || null,
      status: 'pending',
      targetId: null, // Новая запись, нет связи с оригиналом
      createdBy,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

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

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

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

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

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

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

/**
 * Создать черновик для обновления записи (менеджер)
 * Создает запись в blacklist_pending с targetId: <original_id>
 */
export async function updateDraft(
  request: UpdateBlacklistRequest,
  existing: BlacklistEntryRow
): Promise<BlacklistEntryWithMetadata> {
  const { id, name, phone, bookingEngineCheck, comment, updatedBy } = request;

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

  const updates = {
    name: name || existing.name,
    phone: phone || existing.phone,
    bookingEngineCheck: bookingEngineCheck || existing.bookingEngineCheck,
    comment: comment !== undefined ? (comment.trim() || null) : existing.comment,
  };

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

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

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

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

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

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

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

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

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

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

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

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

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