// src/server/features/blacklist/lib/blacklist.service.ts
// Business logic for blacklist management with approval workflow

import { db } from '../../../shared/db/client';
import { blacklist, blacklistPending } from '../db/blacklist.table';
import { employees } from '../../../shared/db/schema';
import { eq, and, or, isNull } from 'drizzle-orm';
import { mapToBlacklistEntry, mapPendingToBlacklistEntryWithMetadata, mapToBlacklistPendingEntry } from './blacklist.mapper';
import { createDraft, updateDraft, deleteRequest } from './blacklist.drafts';
import { executeCreate, executeUpdate, executeDelete, autoApproveDraft, updatePendingDraft, deletePendingDraft } from './blacklist.core';
import type { BlacklistEntry, BlacklistPendingEntry, BlacklistEntryWithMetadata, CreateBlacklistRequest, UpdateBlacklistRequest } from '../blacklist.schema';

/**
 * Создать запись в черном списке
 */
export async function createBlacklistEntry(request: CreateBlacklistRequest): Promise<BlacklistEntryWithMetadata> {
  // АДМИН: Прямое создание в таблице blacklist
  if (request.isAdmin) {
    return executeCreate(request);
  }

  // МЕНЕДЖЕР: Создаем черновик на согласование
  return createDraft(request);
}

/**
 * Обновить запись в черном списке
 */
export async function updateBlacklistEntry(request: UpdateBlacklistRequest): Promise<BlacklistEntryWithMetadata> {
  const { id, name, phone, bookingEngineCheck, comment, updatedBy, isAdmin } = request;

  // 1. Пытаемся найти в основной таблице blacklist
  let existing = await db.select()
    .from(blacklist)
    .where(eq(blacklist.id, id))
    .limit(1);

  let isPendingRecord = false;
  let pendingRecord: typeof blacklistPending.$inferSelect | null = null;

  // 2. Если нет в основной, ищем в таблице черновиков blacklist_pending
  if (!existing[0]) {
    const pendingExisting = await db.select()
      .from(blacklistPending)
      .where(eq(blacklistPending.id, id))
      .limit(1);
    
    if (pendingExisting[0]) {
      existing = pendingExisting as any; // Мапим для совместимости проверок
      pendingRecord = pendingExisting[0]; // Сохраняем оригинальную pending запись
      isPendingRecord = true;
    }
  }

  // 3. Если не нашли ни там, ни там — кидаем ошибку
  if (!existing[0]) {
    throw new Error('Запись не найдена');
  }

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

  // 4. Если это ПРЯМОЕ обновление черновика (Админом или владельцем черновика)
  if (isPendingRecord) {
    // АДМИН: Автоматическое согласование при редактировании черновика
    if (isAdmin) {
      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;

      return autoApproveDraft(id, pendingRecord!, updatedBy, updates);
    }

    // МЕНЕДЖЕР: Обычное обновление черновика (без согласования)
    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;

    return updatePendingDraft(id, updates);
  }

  // 5. Дальше идет старая логика для записей из основной таблицы (blacklist)
  
  // АДМИН: Прямое обновление в таблице blacklist
  if (isAdmin) {
    return executeUpdate(request);
  }

  // МЕНЕДЖЕР: Создаем черновик на согласование
  return updateDraft(request, existing[0]);
}

/**
 * Удалить запись из черного списка (soft delete)
 */
export async function deleteBlacklistEntry(id: string, deletedBy: string, isAdmin: boolean): Promise<void> {
  // 1. Сначала ищем в основной таблице blacklist
  let existing = await db.select()
    .from(blacklist)
    .where(eq(blacklist.id, id))
    .limit(1);

  let isPendingRecord = false;

  // 2. Если не найдено в основной таблице, ищем в blacklist_pending
  if (!existing[0]) {
    const pendingExisting = await db.select()
      .from(blacklistPending)
      .where(eq(blacklistPending.id, id))
      .limit(1);

    if (pendingExisting[0]) {
      existing = pendingExisting as any; // Мапим для совместимости
      isPendingRecord = true;
    }
  }

  // 3. Если не нашли ни там, ни там — кидаем ошибку
  if (!existing[0]) {
    throw new Error('Запись не найдена');
  }

  // 4. Если это удаление черновика (еще не одобренной записи)
  if (isPendingRecord) {
    return deletePendingDraft(id);
  }

  // 5. АДМИН: Физическое удаление (hard delete) из таблицы blacklist
  if (isAdmin) {
    return executeDelete(id);
  }

  // 6. МЕНЕДЖЕР: Создаем запрос на удаление
  return deleteRequest(id, existing[0], deletedBy);
}

/**
 * Получить все записи черного списка (только одобренные)
 */
export async function getAllBlacklistEntries(): Promise<BlacklistEntry[]> {
  const entries = await db.select()
    .from(blacklist)
    .where(isNull(blacklist.archivedAt))
    .orderBy(blacklist.createdAt);

  return entries.map(mapToBlacklistEntry);
}

/**
 * Получить записи по статусу согласования
 */
export async function getBlacklistEntriesByStatus(status: 'pending' | 'approved'): Promise<BlacklistEntry[]> {
  const isApproved = status === 'approved';

  const entries = await db.select()
    .from(blacklist)
    .where(and(
      eq(blacklist.isApproved, isApproved),
      isNull(blacklist.archivedAt)
    ))
    .orderBy(blacklist.createdAt);

  return entries.map(mapToBlacklistEntry);
}

/**
 * Получить запись по ID
 */
export async function getBlacklistEntryById(id: string): Promise<BlacklistEntry | null> {
  const entry = await db.select()
    .from(blacklist)
    .where(eq(blacklist.id, id))
    .limit(1);

  if (!entry[0]) {
    return null;
  }

  return mapToBlacklistEntry(entry[0]);
}

/**
 * Получить все записи из таблицы blacklist_pending со статусом pending или to_delete
 */
export async function getBlacklistPendingEntries(): Promise<BlacklistPendingEntry[]> {
  const entries = await db.select({
    id: blacklistPending.id,
    name: blacklistPending.name,
    phone: blacklistPending.phone,
    bookingEngineCheck: blacklistPending.bookingEngineCheck,
    comment: blacklistPending.comment,
    status: blacklistPending.status,
    targetId: blacklistPending.targetId,
    createdBy: blacklistPending.createdBy,
    reviewedBy: blacklistPending.reviewedBy,
    reviewedAt: blacklistPending.reviewedAt,
    rejectionReason: blacklistPending.rejectionReason,
    createdAt: blacklistPending.createdAt,
    updatedAt: blacklistPending.updatedAt,
    creatorName: employees.fullName,
  })
    .from(blacklistPending)
    .leftJoin(employees, eq(blacklistPending.createdBy, employees.id))
    .where(or(
      eq(blacklistPending.status, 'pending'),
      eq(blacklistPending.status, 'to_delete')
    ))
    .orderBy(blacklistPending.createdAt);

  return entries.map(mapToBlacklistPendingEntry);
}
