/**
 * KB spaces management routes — settings-kb (wave-14).
 *
 * GET    /api/kb/spaces/settings         — list spaces with article counts
 * PATCH  /api/kb/spaces/:id/settings     — rename a space (name + slug)
 * PATCH  /api/kb/spaces/:id/reorder      — update space position
 * DELETE /api/kb/spaces/:id/settings     — delete space if empty
 *
 * All routes require `users:manage` permission.
 * (Basic CRUD is handled by kb.ts; these are settings-page-specific operations.)
 */
import { Hono } from 'hono'
import { z } from 'zod'
import {
  createDb,
  listSpacesWithCounts,
  renameSpace,
  reorderSpace,
  deleteSpaceIfEmpty,
  KbSpaceHasArticlesError,
  KbSpaceNotFoundError,
  KbVaultSpaceDeleteError,
} from '@zync/db/queries'
import type { AppEnv } from '../types'
import { authMiddleware } from '../middleware/auth'
import { requirePermission } from '../middleware/guards'
import { requireModuleEnabled } from '../middleware/require-module-enabled'

const renameSpaceSchema = z.object({
  name: z.string().min(1).max(120),
  slug: z.string().min(1).max(120).regex(/^[a-z0-9-]+$/),
})

const reorderSpaceSchema = z.object({
  position: z.number().int().min(0),
})

export const kbSpacesSettingsRoute = new Hono<AppEnv>()

kbSpacesSettingsRoute.use('*', authMiddleware)
kbSpacesSettingsRoute.use('*', requireModuleEnabled('kb'))

// GET /api/kb/spaces/settings
kbSpacesSettingsRoute.get('/settings', requirePermission('users:manage'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const db = createDb(c.env)
  const spaces = await listSpacesWithCounts(db, session.tid)
  return c.json(spaces, 200)
})

// PATCH /api/kb/spaces/:id/settings (rename)
kbSpacesSettingsRoute.patch('/:id/settings', requirePermission('users:manage'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

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

  const db = createDb(c.env)
  try {
    const space = await renameSpace(
      db,
      session.tid,
      c.req.param('id'),
      parsed.data.name,
      parsed.data.slug,
    )
    return c.json(space, 200)
  } catch (err) {
    if (err instanceof KbSpaceNotFoundError) {
      return c.json({ error: 'Not found' }, 404)
    }
    throw err
  }
})

// PATCH /api/kb/spaces/:id/reorder
kbSpacesSettingsRoute.patch('/:id/reorder', requirePermission('users:manage'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

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

  const db = createDb(c.env)
  try {
    await reorderSpace(db, session.tid, c.req.param('id'), parsed.data.position)
    return c.json({ ok: true }, 200)
  } catch (err) {
    if (err instanceof KbSpaceNotFoundError) {
      return c.json({ error: 'Not found' }, 404)
    }
    throw err
  }
})

// DELETE /api/kb/spaces/:id/settings
kbSpacesSettingsRoute.delete('/:id/settings', requirePermission('users:manage'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const db = createDb(c.env)
  try {
    await deleteSpaceIfEmpty(db, session.tid, c.req.param('id'))
    return c.json({ ok: true }, 200)
  } catch (err) {
    if (err instanceof KbSpaceNotFoundError) {
      return c.json({ error: 'Not found' }, 404)
    }
    if (err instanceof KbVaultSpaceDeleteError) {
      return c.json({ error: err.message }, 403)
    }
    if (err instanceof KbSpaceHasArticlesError) {
      return c.json({ error: err.message, articleCount: err.articleCount }, 409)
    }
    throw err
  }
})
