// src/server/features/reference_books/lib/access.core.ts
// Core admin actions for direct external access operations

import { db } from '@serverShared/db/client';
import { externalAccess, externalAccessPending } from '../db/external_access.table';
import { approvalRequests } from '@features/approval/db/approval_requests.table';
import { eq, and } from 'drizzle-orm';
import { randomUUID } from 'node:crypto';
import { logger } from '@serverShared/lib/logger';
import { notifyAccessUpdate } from './access.notifications';
import { mapToAccessEntry, mapPendingToAccessEntryWithMetadata, type ExternalAccessWithMetadata } from './access.mapper';
import type { CreateAccessRequest, UpdateAccessRequest } from '@shared/contracts/access';

type AccessEntry = typeof externalAccess.$inferSelect;

export async function executeCreate(request: CreateAccessRequest & { createdBy: string }): Promise<ExternalAccessWithMetadata> {
  const { resourceName, link, login, password, comment, createdBy } = request;

  const result = await db.insert(externalAccess)
    .values({
      id: randomUUID(),
      resourceName: resourceName.trim(),
      link: link.trim(),
      login: login.trim(),
      password: password.trim(),
      comment: comment?.trim() || null,
      isApproved: true,
      createdBy,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

  const entry = await db.select().from(externalAccess).where(eq(externalAccess.id, result[0].id)).limit(1);
  if (!entry[0]) {
    throw new Error('Ошибка при создании записи');
  }

  logger.info(`[Access] Entry created by Admin: ${entry[0].resourceName}`);
  await notifyAccessUpdate('access:created', mapToAccessEntry(entry[0]));
  return mapToAccessEntry(entry[0]);
}

export async function executeUpdate(id: string, request: UpdateAccessRequest): Promise<ExternalAccessWithMetadata> {
  const updates: any = { updatedAt: new Date(), isApproved: true };
  if (request.resourceName !== undefined) updates.resourceName = request.resourceName.trim();
  if (request.link !== undefined) updates.link = request.link.trim();
  if (request.login !== undefined) updates.login = request.login.trim();
  if (request.password !== undefined) updates.password = request.password.trim();
  if (request.comment !== undefined) updates.comment = request.comment.trim() || null;

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

  const updated = await db.select().from(externalAccess).where(eq(externalAccess.id, id)).limit(1);
  if (!updated[0]) {
    throw new Error('Запись не найдена');
  }

  logger.info(`[Access] Entry updated by Admin: ${id}`);
  await notifyAccessUpdate('access:updated', mapToAccessEntry(updated[0]));
  return mapToAccessEntry(updated[0]);
}

export async function executeDelete(id: string): Promise<void> {
  await db.delete(externalAccessPending).where(eq(externalAccessPending.targetId, id));

  await db.update(externalAccess)
    .set({ archivedAt: new Date(), updatedAt: new Date() })
    .where(eq(externalAccess.id, id));

  await db.delete(approvalRequests).where(and(
    eq(approvalRequests.entityType, 'access'),
    eq(approvalRequests.targetId, id),
  ));

  logger.info(`[Access] Entry archived by Admin: ${id}`);
  await notifyAccessUpdate('access:deleted', { id, action: 'remove' });
}

export async function autoApproveDraft(
  pendingId: string,
  pendingEntry: typeof externalAccessPending.$inferSelect,
  updatedBy: string,
  updates: any,
): Promise<ExternalAccessWithMetadata> {
  return db.transaction(async (tx) => {
    let finalId: string;

    if (pendingEntry.targetId) {
      await tx.update(externalAccess)
        .set({ ...updates, isApproved: true })
        .where(eq(externalAccess.id, pendingEntry.targetId));

      finalId = pendingEntry.targetId;
      logger.info(`[Access] Admin auto-approved update for pending entry: ${pendingId} -> ${finalId}`);
    } else {
      const result = await tx.insert(externalAccess)
        .values({
          id: randomUUID(),
          resourceName: updates.resourceName,
          link: updates.link,
          login: updates.login,
          password: updates.password,
          comment: updates.comment,
          isApproved: true,
          createdBy: pendingEntry.createdBy || updatedBy,
          createdAt: new Date(),
          updatedAt: updates.updatedAt,
        })
        .$returningId();

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

    await tx.delete(externalAccessPending).where(eq(externalAccessPending.id, pendingId));
    await tx.delete(approvalRequests).where(and(
      eq(approvalRequests.entityType, 'access'),
      eq(approvalRequests.targetId, pendingId),
    ));

    const finalEntry = await tx.select().from(externalAccess).where(eq(externalAccess.id, finalId)).limit(1);
    await notifyAccessUpdate('access:updated', mapToAccessEntry(finalEntry[0]), tx);
    return mapToAccessEntry(finalEntry[0]);
  });
}

export async function updatePendingDraft(id: string, updates: any): Promise<ExternalAccessWithMetadata> {
  await db.update(externalAccessPending).set(updates).where(eq(externalAccessPending.id, id));
  const updated = await db.select().from(externalAccessPending).where(eq(externalAccessPending.id, id)).limit(1);

  logger.info(`[Access] Pending entry updated: ${id} by Manager`);
  await notifyAccessUpdate('access:updated', mapPendingToAccessEntryWithMetadata(updated[0]));
  return mapPendingToAccessEntryWithMetadata(updated[0]);
}

export async function deletePendingDraft(id: string): Promise<void> {
  await db.delete(externalAccessPending).where(eq(externalAccessPending.id, id));

  await db.delete(approvalRequests).where(and(
    eq(approvalRequests.entityType, 'access'),
    eq(approvalRequests.targetId, id),
  ));

  logger.info(`[Access] Pending entry deleted (clean delete): ${id}`);
  await notifyAccessUpdate('access:deleted', { id, action: 'remove' });
}

