import { and, eq, sql } from 'drizzle-orm';
import type { DrizzleClient } from '../client.js';
import { paymentExpectedContracts, paymentFinalizeCheckpoints } from '../schema.js';

export async function fencePaymentFinalizeCheckpoint(
  db: DrizzleClient,
  input: {
    purchaseId: string;
    orderId: string;
    providerPaymentId: string;
    effectKey: string;
    leaseOwner: string;
  },
): Promise<boolean> {
  const rows = await db
    .update(paymentFinalizeCheckpoints)
    .set({ updatedAt: new Date() })
    .where(
      and(
        eq(paymentFinalizeCheckpoints.purchaseId, input.purchaseId),
        eq(paymentFinalizeCheckpoints.orderId, input.orderId),
        eq(paymentFinalizeCheckpoints.effectKey, input.effectKey),
        eq(paymentFinalizeCheckpoints.providerPaymentId, input.providerPaymentId),
        eq(paymentFinalizeCheckpoints.leaseOwner, input.leaseOwner),
        eq(paymentFinalizeCheckpoints.status, 'running'),
        sql`${paymentFinalizeCheckpoints.leaseExpiresAt} > now()`,
      ),
    )
    .returning({ id: paymentFinalizeCheckpoints.id });
  return rows.length === 1;
}

export async function heartbeatPaymentFinalizeCheckpoint(
  db: DrizzleClient,
  input: {
    purchaseId: string;
    orderId: string;
    providerPaymentId: string;
    effectKey: string;
    leaseOwner: string;
    leaseExpiresAt: Date;
  },
): Promise<boolean> {
  const rows = await db
    .update(paymentFinalizeCheckpoints)
    .set({ leaseExpiresAt: input.leaseExpiresAt, updatedAt: new Date() })
    .where(
      and(
        eq(paymentFinalizeCheckpoints.purchaseId, input.purchaseId),
        eq(paymentFinalizeCheckpoints.orderId, input.orderId),
        eq(paymentFinalizeCheckpoints.effectKey, input.effectKey),
        eq(paymentFinalizeCheckpoints.providerPaymentId, input.providerPaymentId),
        eq(paymentFinalizeCheckpoints.leaseOwner, input.leaseOwner),
        eq(paymentFinalizeCheckpoints.status, 'running'),
        sql`${paymentFinalizeCheckpoints.leaseExpiresAt} > now()`,
      ),
    )
    .returning({ id: paymentFinalizeCheckpoints.id });
  return rows.length === 1;
}

export async function completePaymentFinalizeCheckpoint(
  db: DrizzleClient,
  input: {
    purchaseId: string;
    orderId: string;
    providerPaymentId: string;
    effectKey: string;
    leaseOwner: string;
    result: unknown;
  },
): Promise<boolean> {
  const now = new Date();
  const rows = await db
    .update(paymentFinalizeCheckpoints)
    .set({
      status: 'completed',
      result: input.result ?? null,
      updatedAt: now,
      completedAt: now,
      leaseOwner: null,
      leaseExpiresAt: null,
    })
    .where(
      and(
        eq(paymentFinalizeCheckpoints.purchaseId, input.purchaseId),
        eq(paymentFinalizeCheckpoints.orderId, input.orderId),
        eq(paymentFinalizeCheckpoints.effectKey, input.effectKey),
        eq(paymentFinalizeCheckpoints.providerPaymentId, input.providerPaymentId),
        eq(paymentFinalizeCheckpoints.leaseOwner, input.leaseOwner),
        eq(paymentFinalizeCheckpoints.status, 'running'),
        sql`${paymentFinalizeCheckpoints.leaseExpiresAt} > now()`,
      ),
    )
    .returning({ id: paymentFinalizeCheckpoints.id });
  return rows.length === 1;
}

export async function failPaymentFinalizeCheckpoint(
  db: DrizzleClient,
  input: {
    purchaseId: string;
    orderId: string;
    providerPaymentId: string;
    effectKey: string;
    leaseOwner: string;
  },
): Promise<boolean> {
  const rows = await db
    .update(paymentFinalizeCheckpoints)
    .set({ status: 'pending', updatedAt: new Date(), leaseOwner: null, leaseExpiresAt: null })
    .where(
      and(
        eq(paymentFinalizeCheckpoints.purchaseId, input.purchaseId),
        eq(paymentFinalizeCheckpoints.orderId, input.orderId),
        eq(paymentFinalizeCheckpoints.effectKey, input.effectKey),
        eq(paymentFinalizeCheckpoints.providerPaymentId, input.providerPaymentId),
        eq(paymentFinalizeCheckpoints.leaseOwner, input.leaseOwner),
        eq(paymentFinalizeCheckpoints.status, 'running'),
        sql`${paymentFinalizeCheckpoints.leaseExpiresAt} > now()`,
      ),
    )
    .returning({ id: paymentFinalizeCheckpoints.id });
  return rows.length === 1;
}

export async function insertExpectedPaymentContract(
  db: DrizzleClient,
  values: typeof paymentExpectedContracts.$inferInsert,
) {
  return db
    .insert(paymentExpectedContracts)
    .values(values)
    .onConflictDoNothing({ target: paymentExpectedContracts.purchaseId })
    .returning();
}
