/**
 * Admin settlements resource — write commands.
 *
 * markPaid: upsert a payout row with status='paid' + audit log.
 *
 * No raw SQL outside parameterized Drizzle. PII never logged.
 */

import type { DrizzleDb } from '@/server/db/client.js';
import { z } from 'zod';
import { upsertPaidPayout } from '@/server/db/queries/admin-resources/settlements.js';
import type { PayoutRow } from './types.js';

export class SettlementHoldConflictError extends Error {
  readonly code = 'CONFLICT';

  constructor() {
    super('releases still in hold window for period');
    this.name = 'SettlementHoldConflictError';
  }
}

export class SettlementCommandValidationError extends Error {
  readonly code = 'VALIDATION_ERROR';

  constructor() {
    super('Invalid settlement command');
    this.name = 'SettlementCommandValidationError';
  }
}

export interface SettlementAdminPrincipal {
  session: Pick<App.SessionRow, 'id' | 'userId'>;
  user: Pick<App.UserRow, 'id' | 'isAdmin'>;
}

const idSchema = z.uuid();
const periodMonthSchema = z.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/);

// ─── markPaid ─────────────────────────────────────────────────────────────────

interface MarkPaidInput {
  vendorId: string;
  periodMonth: string;
  actor: SettlementAdminPrincipal;
  notes?: string;
}

export async function markPaid(db: DrizzleDb, input: MarkPaidInput): Promise<PayoutRow> {
  const parsed = z
    .object({
      vendorId: idSchema,
      periodMonth: periodMonthSchema,
      actor: z.object({
        session: z.object({ id: z.string().min(1), userId: idSchema }),
        user: z.object({ id: idSchema, isAdmin: z.boolean() }),
      }),
      notes: z.string().max(500).optional(),
    })
    .safeParse(input);
  if (!parsed.success) throw new SettlementCommandValidationError();
  const row = await upsertPaidPayout(db, parsed.data, new SettlementHoldConflictError());

  return {
    id: row.id,
    vendorId: row.vendorId,
    periodMonth: row.periodMonth,
    amountAgorot: row.amountAgorot,
    platformFeeAgorot: row.platformFeeAgorot,
    status: row.status as PayoutRow['status'],
    markedPaidAt: row.markedPaidAt?.toISOString() ?? null,
    markedPaidBy: row.markedPaidBy,
    notes: row.notes,
    stripePayoutId: row.stripePayoutId,
    stripeTransferId: row.stripeTransferId,
    createdAt: row.createdAt.toISOString(),
    updatedAt: row.updatedAt.toISOString(),
  };
}
