/**
 * Custom domain settings — custom-domain-settings-ui (spec 137, wave 11).
 * Mounted at /api/settings/white-label.
 *
 * GET  /          → WhiteLabelConfigRow (Enterprise tier; requires settings:write)
 * POST /          → add/update custom domain (Enterprise)
 * DELETE /        → remove custom domain (Enterprise)
 * POST /verify    → trigger immediate DNS re-check (rate-limited 1/2min per tenant)
 *
 * Non-Enterprise tenants see an upsell card on the frontend; the API returns
 * 403 for non-Enterprise callers on write operations.
 *
 * Note: The backing table is white_label_configs (owned by white-label-api spec 27).
 * tenant_domains as referenced in the plan maps to white_label_configs.
 * This route composes over the existing white-label query helpers.
 */
import { Hono } from 'hono'
import { z } from 'zod'
import type { AppEnv } from '../../types'
import { authMiddleware } from '../../middleware/auth'
import { requirePermission, requireTier } from '../../middleware/guards'
import { TenantTier } from '@zync/types'
import {
  getWhiteLabelConfig,
  upsertWhiteLabelConfig,
  initiateWhiteLabelDomainVerification,
} from '@zync/db/queries'

type WhiteLabelUiReadShape = {
  domain: string | null
  status: 'pending' | 'active' | 'failed' | null
  cname_target: string
  error_message: string | null
  verified_at: string | null
}

function toUiStatus(value: string | null | undefined): WhiteLabelUiReadShape['status'] {
  return value === 'pending' || value === 'active' || value === 'failed' ? value : null
}

// ── Validation ────────────────────────────────────────────────────────────────

// Only subdomain portal domains are accepted — no bare apex domains, no wildcards
function isValidPortalSubdomain(value: string): boolean {
  if (!value || value.includes(' ') || value.includes('*') || value.startsWith('http')) {
    return false
  }
  // Must have at least two labels (subdomain.domain.tld)
  const labels = value.toLowerCase().split('.')
  if (labels.length < 3) return false
  // Each label must be non-empty and DNS-valid
  return labels.every((label) => /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(label))
}

export const CNAME_TARGET = 'portal.zync.is'

const addDomainSchema = z.object({
  domain: z
    .string()
    .toLowerCase()
    .refine(isValidPortalSubdomain, {
      message:
        'Only portal subdomain mapping supported (e.g. portal.acme.com). Bare apex domains, wildcards, and URLs are not accepted.',
    }),
})

// ── Router ────────────────────────────────────────────────────────────────────

export const whiteLabelSettingsRoute = new Hono<AppEnv>()

whiteLabelSettingsRoute.use('*', authMiddleware)

// ── GET /api/settings/white-label ────────────────────────────────────────────

whiteLabelSettingsRoute.get('/', requirePermission('settings:read'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const db = c.get('db')
  const config = await getWhiteLabelConfig(db, session.tid)
  const uiConfig = (config ?? null) as (typeof config & {
    sslVerificationError?: string | null
    verifiedAt?: string | Date | null
  }) | null

  const response: WhiteLabelUiReadShape = {
    domain: uiConfig?.customDomain ?? uiConfig?.portalDomain ?? null,
    status: toUiStatus(uiConfig?.sslStatus),
    cname_target: CNAME_TARGET,
    error_message: uiConfig?.sslVerificationError ?? null,
    verified_at:
      uiConfig?.verifiedAt == null
        ? null
        : uiConfig.verifiedAt instanceof Date
          ? uiConfig.verifiedAt.toISOString()
          : String(uiConfig.verifiedAt),
  }

  return c.json(response, 200)
})

// ── POST /api/settings/white-label (add domain) ───────────────────────────────

whiteLabelSettingsRoute.post(
  '/',
  requirePermission('settings:write'),
  requireTier(TenantTier.ENTERPRISE),
  async (c) => {
    const session = c.get('session')
    if (!session || session.type !== 'user' || !session.tid) {
      return c.json({ error: 'Unauthorized' }, 401)
    }

    const body = await c.req.json().catch(() => null)
    const parsed = addDomainSchema.safeParse(body)
    if (!parsed.success) {
      return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)
    }

    const db = c.get('db')
    const config = await upsertWhiteLabelConfig(db, session.tid, session.sub, {
      customDomain: parsed.data.domain,
      portalDomain: parsed.data.domain,
    })

    return c.json(
      {
        domain: config.customDomain ?? config.portalDomain,
        custom_domain: config.customDomain,
        status: config.sslStatus,
        cname_target: CNAME_TARGET,
      },
      200,
    )
  },
)

// ── DELETE /api/settings/white-label (remove domain) ─────────────────────────

whiteLabelSettingsRoute.delete(
  '/',
  requirePermission('settings:write'),
  requireTier(TenantTier.ENTERPRISE),
  async (c) => {
    const session = c.get('session')
    if (!session || session.type !== 'user' || !session.tid) {
      return c.json({ error: 'Unauthorized' }, 401)
    }

    const db = c.get('db')
    await upsertWhiteLabelConfig(db, session.tid, session.sub, {
      customDomain: null,
      portalDomain: null,
    })

    return c.json({ ok: true }, 200)
  },
)

// ── POST /api/settings/white-label/verify (trigger DNS re-check) ──────────────

whiteLabelSettingsRoute.post(
  '/verify',
  requirePermission('settings:write'),
  requireTier(TenantTier.ENTERPRISE),
  async (c) => {
    const session = c.get('session')
    if (!session || session.type !== 'user' || !session.tid) {
      return c.json({ error: 'Unauthorized' }, 401)
    }

    // Rate-limit: 1 verification attempt per 2 minutes per tenant (via KV)
    const rateLimitKey = `domain-verify:${session.tid}`
    const existing = await c.env.KV.get(rateLimitKey)
    if (existing !== null) {
      return c.json(
        { error: 'Rate limit exceeded. Please wait 2 minutes before retrying.' },
        429,
      )
    }
    await c.env.KV.put(rateLimitKey, '1', { expirationTtl: 120 })

    const db = c.get('db')
    await initiateWhiteLabelDomainVerification(db, session.tid, session.sub)

    return c.json({ ok: true, message: 'Verification initiated. Check back shortly.' }, 200)
  },
)
