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

import { db } from '@serverShared/db/client';
import { blacklist, blacklistPending } from '../db/blacklist.table';
import { approvalRequests } from '@features/approval/db/approval_requests.table';
import { eq, and, isNull } from 'drizzle-orm';
import { randomUUID } from 'node:crypto';
import { logger } from '@serverShared/lib/logger';
import { notifyBlacklistUpdate } from './blacklist.notifications';
import { mapToBlacklistEntry } from './blacklist.mapper';
import type { BlacklistEntry, BlacklistEntryWithMetadata, CreateBlacklistRequest, UpdateBlacklistRequest } from '../blacklist.schema';

/**
 * Прямое создание записи в таблице blacklist (админ)
 */
export async function executeCreate(request: CreateBlacklistRequest): Promise<BlacklistEntry> {
  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('Проверка системы бронирования обязательна');
  }

  const result = await db.insert(blacklist)
    .values({
      id: randomUUID(),
      name: name.trim(),
      phone: phone.trim(),
      bookingEngineCheck,
      comment: comment?.trim() || null,
      isApproved: true,
      createdBy,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

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

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

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

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

  return mapToBlacklistEntry(entry[0]);
}

/**
 * Прямое обновление записи в таблице blacklist (админ)
 */
export async function executeUpdate(request: UpdateBlacklistRequest): Promise<BlacklistEntry> {
  const { id, name, phone, bookingEngineCheck, comment } = request;

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

  if (name !== undefined) {
    updates.name = name.trim();
  }
  if (phone !== undefined) {
    updates.phone = phone.trim();
  }
  if (bookingEngineCheck !== undefined) {
    updates.bookingEngineCheck = bookingEngineCheck;
  }
  if (comment !== undefined) {
    updates.comment = comment.trim() || null;
  }

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

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

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

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

  return mapToBlacklistEntry(updated[0]);
}

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

  // Физическое удаление оригинальной записи
  await db.delete(blacklist)
    .where(eq(blacklist.id, id));

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

  logger.info(`[Blacklist] Entry hard deleted by Admin: ${id}`);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  return mapPendingToBlacklistEntryWithMetadata(updated[0]);
}

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

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

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

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