/**
 * Payment gateway query helpers — payment-gateway-adapters (wave-10 leaf 5).
 *
 * Covers:
 *  - getPaymentGatewayConfig      — load config (with decrypted credentials)
 *  - getPaymentGatewayConfigMasked — load config summary (no secrets)
 *  - upsertPaymentGatewayConfig   — encrypt + store gateway config
 *  - getPaymentLinkForInvoice     — return stored payment link metadata
 *
 * Credentials: AES-256-GCM via encryptCredential from @zync/utils.
 * encrypted_config = JSON.stringify({ ciphertext, iv, authTag }).
 * NEVER store payment credentials in plaintext.
 *
 * Route files MUST NOT import raw Drizzle tables — they call these helpers.
 */
import { eq } from 'drizzle-orm'
import { z } from 'zod'
import type { Db } from '../client'
import { paymentGatewayConfigs, type PaymentGateway } from '../schema/payment-gateways'
import { encryptCredential, decryptCredential } from '@zync/utils'
import { auditLog } from './_audit-forward'

// ── Zod schemas ───────────────────────────────────────────────────────────────

export const upsertPaymentGatewaySchema = z.object({
  gateway: z.enum(['cardcom', 'payplus', 'stripe']),
  isActive: z.boolean().optional().default(false),
  testMode: z.boolean().optional().default(true),
  // Gateway-specific config fields (API key, terminal ID, etc.)
  config: z.record(z.string()),
})

export type UpsertPaymentGatewayInput = z.infer<typeof upsertPaymentGatewaySchema>

// ── Public interfaces ─────────────────────────────────────────────────────────

export interface PaymentGatewayConfigFull {
  gateway: PaymentGateway
  isActive: boolean
  testMode: boolean
  config: Record<string, string> // plaintext
}

export interface PaymentGatewayConfigMasked {
  gateway: PaymentGateway
  isActive: boolean
  testMode: boolean
  configured: boolean
}

// ── Helpers ────────────────────────────────────────────────────────────────────

function getEncryptionKey(): string {
  const key = process.env['INTEGRATION_ENCRYPTION_KEY']
  if (!key) throw new Error('INTEGRATION_ENCRYPTION_KEY env not set')
  return key
}

// ── Queries ───────────────────────────────────────────────────────────────────

/**
 * Load and decrypt gateway config for a tenant.
 * Returns null if not configured.
 */
export async function getPaymentGatewayConfig(
  db: Db,
  tenantId: string,
): Promise<PaymentGatewayConfigFull | null> {
  const rows = await db
    .select()
    .from(paymentGatewayConfigs)
    .where(eq(paymentGatewayConfigs.tenantId, tenantId))
    .limit(1)

  const row = rows[0]
  if (!row) return null

  const encryptionKey = getEncryptionKey()
  const blob = JSON.parse(row.encryptedConfig) as { ciphertext: string; iv: string; authTag: string }
  const plaintext = await decryptCredential(blob, encryptionKey)
  const config = JSON.parse(plaintext) as Record<string, string>

  return {
    gateway: row.gateway as PaymentGateway,
    isActive: row.isActive,
    testMode: row.testMode,
    config,
  }
}

/**
 * Return masked summary (no secrets) for GET settings endpoint.
 */
export async function getPaymentGatewayConfigMasked(
  db: Db,
  tenantId: string,
): Promise<PaymentGatewayConfigMasked | null> {
  const rows = await db
    .select({
      gateway: paymentGatewayConfigs.gateway,
      isActive: paymentGatewayConfigs.isActive,
      testMode: paymentGatewayConfigs.testMode,
    })
    .from(paymentGatewayConfigs)
    .where(eq(paymentGatewayConfigs.tenantId, tenantId))
    .limit(1)

  const row = rows[0]
  if (!row) return null

  return {
    gateway: row.gateway as PaymentGateway,
    isActive: row.isActive,
    testMode: row.testMode,
    configured: true,
  }
}

/**
 * Encrypt + store gateway config. Upserts on tenant_id conflict.
 * Writes audit log in the same transaction.
 */
export async function upsertPaymentGatewayConfig(
  db: Db,
  tenantId: string,
  userId: string,
  input: UpsertPaymentGatewayInput,
): Promise<void> {
  const encryptionKey = getEncryptionKey()
  const blob = await encryptCredential(JSON.stringify(input.config), encryptionKey)
  const encryptedConfig = JSON.stringify(blob)

  await db.transaction(async (tx) => {
    await tx
      .insert(paymentGatewayConfigs)
      .values({
        tenantId,
        gateway: input.gateway,
        encryptedConfig,
        isActive: input.isActive,
        testMode: input.testMode,
      })
      .onConflictDoUpdate({
        target: [paymentGatewayConfigs.tenantId],
        set: {
          gateway: input.gateway,
          encryptedConfig,
          isActive: input.isActive,
          testMode: input.testMode,
          updatedAt: new Date(),
        },
      })

    await tx.insert(auditLog).values({
      tenantId,
      actorId: userId,
      actorType: 'user',
      entityType: 'payment_gateway_config',
      entityId: tenantId,
      action: 'settings.updated',
      changes: { field: ['payment_gateway', input.gateway] as [unknown, unknown] },
    })
  })
}

/**
 * Get payment link metadata for an invoice.
 * Returns null if no link has been generated.
 * Note: payment links are not persisted in DB — returned from integration call.
 * This stub exists for future caching; currently always returns null.
 */
export async function getPaymentLinkForInvoice(
  _db: Db,
  _tenantId: string,
  _invoiceId: string,
): Promise<{ url: string; expiresAt: string | null } | null> {
  // Future: query a payment_links table for cached URLs.
  return null
}
