/**
 * Admin image-moderation resource — write actions.
 *
 * - approveImage: set approvalStatus=APPROVED, write audit log.
 * - rejectImage: cascade reject (entity state + outbox) + audit log.
 * - updateVendorHeroApproval: simple status update.
 * - forceApproveVendorHero: admin override of pending vendor hero image.
 *
 * All admin actions write to admin_actions audit table.
 */

import { eq } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client.js';
import { imageUploads, vendors } from '@/server/db/schema.js';
import { recordAdminAction } from '@/server/db/queries/admin-actions.js';
import { setImageApprovalStatus } from '@/server/db/queries/image-uploads.js';
import {
  approveVendorHeroPending,
  setVendorHeroApprovalStatus,
} from '@/server/db/queries/vendors.js';
import { rejectImageWithCascade } from './cascade.js';
import { ImageModerationError } from './errors.js';

// ─── approveImage ─────────────────────────────────────────────────────────────

export async function approveImage(
  db: DrizzleClient,
  imageId: string,
  adminId: string,
): Promise<void> {
  const [image] = await db
    .select({ id: imageUploads.id, approvalStatus: imageUploads.approvalStatus })
    .from(imageUploads)
    .where(eq(imageUploads.id, imageId))
    .limit(1);

  if (!image) {
    throw new ImageModerationError('IMAGE_NOT_FOUND', 'Image not found');
  }

  await setImageApprovalStatus(db, imageId, 'APPROVED');

  await recordAdminAction(db, {
    adminId,
    targetType: 'USER',
    targetId: imageId,
    action: 'APPROVE',
    note: `Image approved: ${imageId}`,
  });
}

// ─── rejectImage ──────────────────────────────────────────────────────────────

/**
 * Human-admin reject: runs cascade side effects (entity state update,
 * outbox notification) via the cascade registry, then writes an audit log.
 *
 * @param reason  Optional override reason from the admin's textarea. Falls
 *                back to the AI reason stored on the image, or 'unspecified'.
 */
export async function rejectImage(
  db: DrizzleClient,
  imageId: string,
  adminId: string,
  reason?: string | null,
): Promise<void> {
  const [image] = await db
    .select({ id: imageUploads.id, approvalStatus: imageUploads.approvalStatus })
    .from(imageUploads)
    .where(eq(imageUploads.id, imageId))
    .limit(1);

  if (!image) {
    throw new ImageModerationError('IMAGE_NOT_FOUND', 'Image not found');
  }

  // Cascade registry handles entity state + outbox notification
  await rejectImageWithCascade(db, imageId, reason ?? null);

  // Overwrite the audit adminId with the human admin (cascade writes adminId=null for AI)
  await recordAdminAction(db, {
    adminId,
    targetType: 'USER',
    targetId: imageId,
    action: 'REJECT',
    note: reason ? `Image rejected: ${reason}` : `Image rejected: ${imageId}`,
  });
}

// ─── updateVendorHeroApproval ─────────────────────────────────────────────────

export async function updateVendorHeroApproval(
  db: DrizzleClient,
  vendorId: string,
  status: 'APPROVED' | 'REJECTED',
): Promise<{ id: string } | null> {
  return setVendorHeroApprovalStatus(db, vendorId, status);
}

// ─── forceApproveVendorHero ───────────────────────────────────────────────────

export async function forceApproveVendorHero(
  db: DrizzleClient,
  vendorId: string,
  adminId: string,
): Promise<void> {
  const [vendor] = await db
    .select({ heroPendingImageUrl: vendors.heroPendingImageUrl })
    .from(vendors)
    .where(eq(vendors.id, vendorId))
    .limit(1);

  if (!vendor?.heroPendingImageUrl) {
    throw new ImageModerationError('IMAGE_NOT_FOUND', 'No pending hero image to approve');
  }

  await approveVendorHeroPending(db, vendorId);

  await recordAdminAction(db, {
    adminId,
    targetType: 'USER',
    targetId: vendorId,
    action: 'APPROVE',
    note: `Force-approved vendor hero image for vendor ${vendorId}`,
  });
}
