/**
 * Scheduling connection management routes — calendar-module.
 * Mounted at /api/calendar/scheduling (via router.ts).
 *
 * POST   /scheduling/:provider         upsert scheduling connection (settings:write)
 * POST   /scheduling/:provider/test    test API key reachability
 * DELETE /scheduling/:provider         remove connection + unregister webhook
 */
import { Hono } from 'hono'
import type { AppEnv } from '../../types'
import { requirePermission } from '../../middleware/guards'
import {
  upsertSchedulingConnection,
  getSchedulingConnection,
  deleteSchedulingConnection,
  listSchedulingConnections,
} from '@zync/db/queries'
import { encryptToken, decryptToken } from '@zync/calendar/server'
import { createSchedulingConnectionSchema, schedulingProviderSchema } from './validation'
import type { SchedulingConnectionObject, SchedulingProvider } from '@zync/calendar'
import type { SchedulingConnectionRow } from '@zync/db/queries'

export const schedulingSettingsRoute = new Hono<AppEnv>()

function serializeSchedulingConnection(row: SchedulingConnectionRow): SchedulingConnectionObject {
  return {
    id: row.id,
    tenantId: row.tenantId,
    provider: row.provider as SchedulingProvider,
    webhookUri: row.webhookUri ?? null,
    settings: row.settings as Record<string, unknown> | null,
    createdAt: row.createdAt.toISOString(),
    // api_key intentionally omitted
  }
}

// ── GET /scheduling ───────────────────────────────────────────────────────────

schedulingSettingsRoute.get('/scheduling', 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 rows = await listSchedulingConnections(db, session.tid)
  return c.json({ connections: rows.map(serializeSchedulingConnection) }, 200)
})

// ── POST /scheduling/:provider ────────────────────────────────────────────────

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

  const providerResult = schedulingProviderSchema.safeParse(c.req.param('provider'))
  if (!providerResult.success) {
    return c.json({ error: 'Invalid provider. Must be one of: calendly, acuity, mocal' }, 400)
  }

  const parsed = createSchedulingConnectionSchema.safeParse(await c.req.json())
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', issues: parsed.error.issues }, 400)
  }

  const encryptionKey = c.env.INTEGRATION_ENCRYPTION_KEY
  if (!encryptionKey) {
    return c.json({ error: 'Encryption key not configured' }, 500)
  }

  const encryptedApiKey = await encryptToken(parsed.data.apiKey, encryptionKey)

  // Build a webhook URI for this tenant + provider
  const webhookUri = `${new URL(c.req.url).origin}/api/webhooks/scheduling/${providerResult.data}`

  const db = c.get('db')
  const row = await upsertSchedulingConnection(db, {
    tenantId: session.tid,
    provider: providerResult.data,
    apiKey: encryptedApiKey,
    webhookUri,
    settings: parsed.data.settings ?? {},
  })

  return c.json(serializeSchedulingConnection(row), 200)
})

// ── POST /scheduling/:provider/test ──────────────────────────────────────────

schedulingSettingsRoute.post('/scheduling/:provider/test', requirePermission('settings:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const providerResult = schedulingProviderSchema.safeParse(c.req.param('provider'))
  if (!providerResult.success) {
    return c.json({ error: 'Invalid provider' }, 400)
  }

  const encryptionKey = c.env.INTEGRATION_ENCRYPTION_KEY
  if (!encryptionKey) {
    return c.json({ error: 'Encryption key not configured' }, 500)
  }

  const db = c.get('db')
  const conn = await getSchedulingConnection(db, session.tid, providerResult.data)
  if (!conn) {
    return c.json({ error: 'No connection found for this provider' }, 404)
  }

  let reachable = false
  let errorMessage: string | null = null

  try {
    const apiKey = await decryptToken(conn.apiKey, encryptionKey)
    const provider = providerResult.data

    // Provider-specific ping endpoints
    const pingUrl =
      provider === 'calendly'
        ? 'https://api.calendly.com/users/me'
        : provider === 'acuity'
        ? 'https://acuityscheduling.com/api/v1/me'
        : 'https://api.mocal.io/v1/ping' // mocal placeholder

    const authHeader =
      provider === 'calendly'
        ? `Bearer ${apiKey}`
        : provider === 'acuity'
        ? `Basic ${btoa(apiKey)}`
        : `Bearer ${apiKey}`

    const res = await fetch(pingUrl, {
      headers: { Authorization: authHeader },
    })
    reachable = res.ok
    if (!res.ok) {
      errorMessage = `Provider returned ${res.status}`
    }
  } catch (e) {
    errorMessage = e instanceof Error ? e.message : 'Unknown error'
  }

  return c.json({ reachable, error: errorMessage }, 200)
})

// ── DELETE /scheduling/:provider ──────────────────────────────────────────────

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

  const providerResult = schedulingProviderSchema.safeParse(c.req.param('provider'))
  if (!providerResult.success) {
    return c.json({ error: 'Invalid provider' }, 400)
  }

  const db = c.get('db')
  const deleted = await deleteSchedulingConnection(db, session.tid, providerResult.data)
  if (!deleted) {
    return c.json({ error: 'No connection found for this provider' }, 404)
  }

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