// src/server/features/reference_books/lib/access.drafts.ts
// Drafting logic for external access approval workflow

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

type AccessEntryRow = typeof externalAccess.$inferSelect;

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

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

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

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

  await createApprovalRequest({
    entityType: 'access',
    targetId: pendingEntry[0].id,
    requesterId: createdBy,
    payload: {
      resourceName: pendingEntry[0].resourceName,
      login: pendingEntry[0].login,
      action: 'create',
    },
  });

  await notifyAccessUpdate('access:created', mapPendingToAccessEntryWithMetadata(pendingEntry[0]));
  return mapPendingToAccessEntryWithMetadata(pendingEntry[0]);
}

export async function updateDraft(
  request: UpdateAccessRequest & { id: string; updatedBy: string },
  existing: AccessEntryRow,
): Promise<ExternalAccessWithMetadata> {
  const { id, updatedBy } = request;

  const updates = {
    resourceName: request.resourceName !== undefined ? request.resourceName : existing.resourceName,
    link: request.link !== undefined ? request.link : existing.link,
    login: request.login !== undefined ? request.login : existing.login,
    password: request.password !== undefined ? request.password : existing.password,
    comment: request.comment !== undefined ? (request.comment.trim() || null) : existing.comment,
  };

  const result = await db.insert(externalAccessPending)
    .values({
      id: randomUUID(),
      resourceName: updates.resourceName.trim(),
      link: updates.link.trim(),
      login: updates.login.trim(),
      password: updates.password.trim(),
      comment: updates.comment,
      status: 'pending',
      targetId: id,
      createdBy: updatedBy,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

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

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

  await createApprovalRequest({
    entityType: 'access',
    targetId: pendingEntry[0].id,
    requesterId: updatedBy,
    payload: {
      originalId: id,
      resourceName: updates.resourceName,
      login: updates.login,
      action: 'update',
    },
  });

  await notifyAccessUpdate('access:updated', mapPendingToAccessEntryWithMetadata(pendingEntry[0]));
  return mapPendingToAccessEntryWithMetadata(pendingEntry[0]);
}

export async function deleteRequest(id: string, existing: AccessEntryRow, deletedBy: string): Promise<void> {
  const result = await db.insert(externalAccessPending)
    .values({
      id: randomUUID(),
      resourceName: existing.resourceName,
      link: existing.link,
      login: existing.login,
      password: existing.password,
      comment: existing.comment,
      status: 'to_delete',
      targetId: id,
      createdBy: deletedBy,
      createdAt: new Date(),
      updatedAt: new Date(),
    })
    .$returningId();

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

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

  await createApprovalRequest({
    entityType: 'access',
    targetId: pendingEntry[0].id,
    requesterId: deletedBy,
    payload: {
      originalId: id,
      resourceName: existing.resourceName,
      login: existing.login,
      action: 'delete',
    },
  });

  await notifyAccessUpdate('access:updated', mapPendingToAccessEntryWithMetadata(pendingEntry[0]));
}

