/**
 * White-label configuration query helpers — white-label-api (wave-10 leaf 7).
 *
 * Manages custom domain, SSL status, and brand configuration per tenant.
 * All helpers are tenant-scoped.
 *
 * Zod schemas re-exported for route-side validation.
 */
import { eq, sql } from 'drizzle-orm'
import { z } from 'zod'
import type { Db } from '../client'
import { whiteLabelConfigs } from '../schema/white-label'
import type { WhiteLabelConfigRow } from '../schema/white-label'
import { auditLog } from './_audit-forward'

export type { WhiteLabelConfigRow }

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

export const upsertWhiteLabelSchema = z.object({
  customDomain: z.string().min(3).max(253).optional().nullable(),
  brandName: z.string().min(1).max(100).optional(),
  logoUrl: z.string().url().optional().nullable(),
  primaryColor: z.string().regex(/^#[0-9a-fA-F]{6}$/, 'Must be a hex color').optional().nullable(),
  faviconUrl: z.string().url().optional().nullable(),
  customCss: z.string().max(50000).optional().nullable(),
  apiDomain: z.string().min(3).max(253).optional().nullable(),
  portalDomain: z.string().min(3).max(253).optional().nullable(),
})

export type UpsertWhiteLabelInput = z.infer<typeof upsertWhiteLabelSchema>

// ── Read helpers ──────────────────────────────────────────────────────────────

/**
 * Get the white-label config for a tenant. Returns null if not yet configured.
 */
export async function getWhiteLabelConfig(
  db: Db,
  tenantId: string,
): Promise<WhiteLabelConfigRow | null> {
  const [row] = await db
    .select()
    .from(whiteLabelConfigs)
    .where(eq(whiteLabelConfigs.tenantId, tenantId))
    .limit(1)
  return row ?? null
}

/**
 * Resolve a tenant by custom domain. Used for request routing.
 * Returns the full config row (including tenantId) or null.
 */
export async function getWhiteLabelByDomain(
  db: Db,
  domain: string,
): Promise<WhiteLabelConfigRow | null> {
  const [row] = await db
    .select()
    .from(whiteLabelConfigs)
    .where(sql`${whiteLabelConfigs.customDomain} = ${domain} OR ${whiteLabelConfigs.portalDomain} = ${domain}`)
    .limit(1)
  return row ?? null
}

// ── Write helpers ─────────────────────────────────────────────────────────────

/**
 * Create or update the white-label config for a tenant.
 * Resets sslStatus to 'pending' if customDomain changes.
 */
export async function upsertWhiteLabelConfig(
  db: Db,
  tenantId: string,
  actorUserId: string,
  data: UpsertWhiteLabelInput,
): Promise<WhiteLabelConfigRow> {
  const existing = await getWhiteLabelConfig(db, tenantId)

  const normalizedData: UpsertWhiteLabelInput = {
    ...data,
  }
  if (normalizedData.customDomain !== undefined && normalizedData.portalDomain === undefined) {
    normalizedData.portalDomain = normalizedData.customDomain
  }
  if (normalizedData.portalDomain !== undefined && normalizedData.customDomain === undefined) {
    normalizedData.customDomain = normalizedData.portalDomain
  }

  // Reset SSL status if domain is being changed
  const domainChanged =
    normalizedData.customDomain !== undefined && normalizedData.customDomain !== existing?.customDomain
  const sslStatus = domainChanged ? 'pending' : (existing?.sslStatus ?? 'pending')

  const now = new Date()

  return db.transaction(async (tx) => {
    let row: WhiteLabelConfigRow

    if (existing) {
      const [updated] = await tx
        .update(whiteLabelConfigs)
        .set({
          ...data,
          ...normalizedData,
          sslStatus,
          updatedAt: now,
        })
        .where(eq(whiteLabelConfigs.tenantId, tenantId))
        .returning()
      if (!updated) throw new Error('upsertWhiteLabelConfig: update returned no row')
      row = updated
    } else {
      const [inserted] = await tx
        .insert(whiteLabelConfigs)
        .values({
          tenantId,
          ...normalizedData,
          sslStatus: 'pending',
          createdAt: now,
          updatedAt: now,
        })
        .returning()
      if (!inserted) throw new Error('upsertWhiteLabelConfig: insert returned no row')
      row = inserted
    }

    await tx.insert(auditLog).values({
      tenantId,
      actorId: actorUserId,
      actorType: 'user',
      entityType: 'white_label_config',
      entityId: row.id,
      action: existing ? 'update_white_label' : 'create_white_label',
      changes: Object.fromEntries(
        Object.entries(data).map(([k, v]) => [k, [null, v]]),
      ),
    })

    return row
  })
}

/**
 * Initiate DNS verification for a custom domain.
 * Sets sslStatus back to 'pending' and records the attempt.
 * Returns the required CNAME target for the tenant to configure.
 */
export async function initiateWhiteLabelDomainVerification(
  db: Db,
  tenantId: string,
  actorUserId: string,
): Promise<{ cnameTarget: string }> {
  const config = await getWhiteLabelConfig(db, tenantId)
  if (!config) {
    throw new Error('No custom domain configured')
  }

  const domain = config.customDomain ?? config.portalDomain
  if (!domain) {
    throw new Error('No custom domain configured')
  }

  await db.transaction(async (tx) => {
    await tx
      .update(whiteLabelConfigs)
      .set({ sslStatus: 'pending', updatedAt: new Date() })
      .where(eq(whiteLabelConfigs.tenantId, tenantId))

    await tx.insert(auditLog).values({
      tenantId,
      actorId: actorUserId,
      actorType: 'user',
      entityType: 'white_label_config',
      entityId: config.id,
      action: 'initiate_domain_verification',
      changes: { domain: [null, domain] },
    })
  })

  return { cnameTarget: 'portal.zync.is' }
}
