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

import { db } from '@serverShared/db/client';
import { inventoryTable, inventoryPendingTable } from '../db/inventory.table';
import { eq } from 'drizzle-orm';
import { randomUUID } from 'node:crypto';
import { logger } from '@serverShared/lib/logger';
import type { InventoryPendingInsert } from '../db/inventory.table';
import type { InventoryUpdateRequest } from '@shared/contracts/inventory';

// Type for inventory pending entry
type InventoryPendingEntry = typeof inventoryPendingTable.$inferSelect;

/**
 * Create draft inventory entry (Manager only)
 */
export async function createDraftInventory(data: any, userId: string): Promise<InventoryPendingEntry> {
  const insertData: InventoryPendingInsert = {
    ...data,
    status: 'pending',
    createdBy: userId,
    createdAt: new Date(),
    updatedAt: new Date(),
  };

  const result = await db.insert(inventoryPendingTable).values(insertData).$returningId();
  if (!result || !result[0]) {
    throw new Error('Failed to create draft inventory entry');
  }

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

  if (!finalEntry[0]) {
    throw new Error('Failed to retrieve created draft inventory entry');
  }

  logger.info(`[Inventory] Draft created by Manager: ${finalEntry[0].name}`);

  return finalEntry[0];
}

/**
 * Update draft inventory entry (Manager only)
 * Creates a new pending entry with targetId pointing to the original
 */
export async function createUpdateRequestInventory(
  id: string,
  request: InventoryUpdateRequest,
  existing: typeof inventoryTable.$inferSelect,
  userId: string,
): Promise<InventoryPendingEntry> {
  const { name, category, quantity, unit, location, comment, weightPerUnit, manufacturer, model, serialNumber, orderingLink, articleNumber } = request;

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

  const updates = {
    name: name || existing.name,
    category: category || existing.category,
    quantity: quantity || existing.quantity,
    unit: unit !== undefined ? unit : existing.unit,
    location: location || existing.location,
    comment: comment !== undefined ? (comment?.trim() || null) : existing.comment,
    weightPerUnit: weightPerUnit !== undefined ? weightPerUnit : existing.weightPerUnit,
    manufacturer: manufacturer !== undefined ? (manufacturer?.trim() || null) : existing.manufacturer,
    model: model !== undefined ? (model?.trim() || null) : existing.model,
    serialNumber: serialNumber !== undefined ? (serialNumber?.trim() || null) : existing.serialNumber,
    orderingLink: orderingLink !== undefined ? (orderingLink?.trim() || null) : existing.orderingLink,
    articleNumber: articleNumber !== undefined ? (articleNumber?.trim() || null) : existing.articleNumber,
  };

  const result = await db.insert(inventoryPendingTable)
    .values({
      id: randomUUID(),
      name: updates.name.trim(),
      category: updates.category.trim(),
      quantity: updates.quantity,
      unit: updates.unit,
      location: updates.location.trim(),
      comment: updates.comment,
      weightPerUnit: updates.weightPerUnit,
      manufacturer: updates.manufacturer,
      model: updates.model,
      serialNumber: updates.serialNumber,
      orderingLink: updates.orderingLink,
      articleNumber: updates.articleNumber,
      status: 'pending',
      targetId: id, // Ссылка на оригинальную запись
      createdBy: userId,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

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

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

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

  return pendingEntry[0];
}

/**
 * Обновить существующую заявку её автором без создания дубликата.
 */
export async function updatePendingInventory(
  id: string,
  request: InventoryUpdateRequest,
): Promise<InventoryPendingEntry> {
  const updates: Partial<InventoryPendingInsert> = { updatedAt: new Date() };
  if (request.name !== undefined) updates.name = request.name.trim();
  if (request.category !== undefined) updates.category = request.category.trim();
  if (request.quantity !== undefined) updates.quantity = request.quantity;
  if (request.unit !== undefined) updates.unit = request.unit;
  if (request.location !== undefined) updates.location = request.location.trim();
  if (request.comment !== undefined) updates.comment = request.comment?.trim() || null;
  if (request.weightPerUnit !== undefined) updates.weightPerUnit = request.weightPerUnit;
  if (request.manufacturer !== undefined) updates.manufacturer = request.manufacturer?.trim() || null;
  if (request.model !== undefined) updates.model = request.model?.trim() || null;
  if (request.serialNumber !== undefined) updates.serialNumber = request.serialNumber?.trim() || null;
  if (request.orderingLink !== undefined) updates.orderingLink = request.orderingLink?.trim() || null;
  if (request.articleNumber !== undefined) updates.articleNumber = request.articleNumber?.trim() || null;

  await db.update(inventoryPendingTable).set(updates).where(eq(inventoryPendingTable.id, id));
  const [updated] = await db.select().from(inventoryPendingTable).where(eq(inventoryPendingTable.id, id)).limit(1);
  if (!updated) throw new Error('Заявка инвентаря не найдена');
  return updated;
}

/**
 * Delete draft inventory entry (Manager only)
 */
export async function deleteDraftInventory(id: string): Promise<void> {
  await db.delete(inventoryPendingTable).where(eq(inventoryPendingTable.id, id));
  logger.info(`[Inventory] Draft deleted by Manager: ${id}`);
}

/**
 * Create a delete request for an inventory item (Manager only)
 * Copies the item to pending table with 'to_delete' status
 */
export async function createDeleteRequestInventory(originalItem: any, userId: string) {
  const insertData = {
    ...originalItem, // Copy all fields (name, category, etc.)
    id: randomUUID(), // New ID for the draft
    targetId: originalItem.id, // Link to original
    status: 'to_delete',
    createdBy: userId,
    createdAt: new Date(),
    updatedAt: new Date(),
    // Ensure we don't copy system fields that shouldn't be there
    archivedAt: null,
  };

  await db.insert(inventoryPendingTable).values(insertData);
  logger.info(`[Inventory] Delete request created for: ${originalItem.name}`);
}
