/**
 * Project templates route group — project-template-gallery.
 * Mounted at /api/project-templates in routes/index.ts (via manifest).
 *
 * All sub-routes run behind authMiddleware + requireModuleEnabled('projects').
 *
 * GET    /                         → list templates (system + tenant own)
 * POST   /                         → create template
 * GET    /:id                      → template detail + tasks
 * PATCH  /:id                      → edit template (tenant-owned only)
 * DELETE /:id                      → delete template (tenant-owned only)
 * GET    /:id/tasks                → list template tasks
 * POST   /:id/tasks                → add template task
 * PATCH  /:id/tasks/:tid           → edit template task
 * DELETE /:id/tasks/:tid           → remove template task
 * POST   /from-project/:projectId  → save existing project as template
 * POST   /instantiate              → create project from template
 */
import { Hono } from 'hono'
import type { AppEnv } from '../../types'
import { authMiddleware } from '../../middleware/auth'
import { requireModuleEnabled } from '../../middleware/require-module-enabled'
import { requirePermission } from '../../middleware/guards'
import {
  listTemplates,
  getTemplate,
  getTemplateTasks,
  createTemplate,
  updateTemplate,
  deleteTemplate,
  addTemplateTask,
  updateTemplateTask,
  deleteTemplateTask,
  instantiateTemplate,
  saveProjectAsTemplate,
  createTemplateSchema,
  updateTemplateSchema,
  createTemplateTaskSchema,
  updateTemplateTaskSchema,
  instantiateTemplateSchema,
  saveAsTemplateSchema,
} from '@zync/db/queries'

const projectTemplatesRoute = new Hono<AppEnv>()

projectTemplatesRoute.use('*', authMiddleware)
projectTemplatesRoute.use('*', requireModuleEnabled('projects'))

// ── GET / — list templates ────────────────────────────────────────────────────
projectTemplatesRoute.get('/', requirePermission('projects: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 category = c.req.query('category') || undefined
  const q = c.req.query('q') || undefined
  const page = Number(c.req.query('page') ?? '1')
  const pageSize = Number(c.req.query('pageSize') ?? '20')
  const result = await listTemplates(db, session.tid, { category, q, page, pageSize })
  return c.json(result, 200)
})

// ── POST / — create template ──────────────────────────────────────────────────
projectTemplatesRoute.post('/', requirePermission('projects:write'), 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 = createTemplateSchema.safeParse(body)
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', issues: parsed.error.issues }, 400)
  }
  const db = c.get('db')
  const row = await createTemplate(db, session.tid, parsed.data, session.sub)
  return c.json(row, 201)
})

// ── GET /:id — template detail + tasks ───────────────────────────────────────
projectTemplatesRoute.get('/:id', requirePermission('projects: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 template = await getTemplate(db, c.req.param('id'), session.tid)
  if (!template) return c.json({ error: 'Not found' }, 404)
  const templateTasks = await getTemplateTasks(db, template.id, session.tid)
  return c.json({ template, tasks: templateTasks }, 200)
})

// ── PATCH /:id — edit template ────────────────────────────────────────────────
projectTemplatesRoute.patch('/:id', requirePermission('projects:write'), 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 = updateTemplateSchema.safeParse(body)
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', issues: parsed.error.issues }, 400)
  }
  const db = c.get('db')
  const row = await updateTemplate(db, session.tid, c.req.param('id'), parsed.data)
  if (!row) return c.json({ error: 'Not found or not editable' }, 404)
  return c.json(row, 200)
})

// ── DELETE /:id — delete template ─────────────────────────────────────────────
projectTemplatesRoute.delete('/:id', requirePermission('projects:write'), 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 ok = await deleteTemplate(db, session.tid, c.req.param('id'))
  if (!ok) return c.json({ error: 'Not found or not deletable' }, 404)
  return c.json({ ok: true }, 200)
})

// ── GET /:id/tasks — list template tasks ──────────────────────────────────────
projectTemplatesRoute.get('/:id/tasks', requirePermission('projects: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 getTemplateTasks(db, c.req.param('id'), session.tid)
  if (rows.length === 0) {
    const template = await getTemplate(db, c.req.param('id'), session.tid)
    if (!template) return c.json({ error: 'Not found' }, 404)
  }
  return c.json({ rows }, 200)
})

// ── POST /:id/tasks — add template task ───────────────────────────────────────
projectTemplatesRoute.post('/:id/tasks', requirePermission('projects:write'), 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 = createTemplateTaskSchema.safeParse(body)
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', issues: parsed.error.issues }, 400)
  }
  const db = c.get('db')
  const row = await addTemplateTask(db, session.tid, c.req.param('id'), parsed.data)
  if (!row) return c.json({ error: 'Not found or not editable' }, 404)
  return c.json(row, 201)
})

// ── PATCH /:id/tasks/:tid — edit template task ────────────────────────────────
projectTemplatesRoute.patch('/:id/tasks/:tid', requirePermission('projects:write'), 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 = updateTemplateTaskSchema.safeParse(body)
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', issues: parsed.error.issues }, 400)
  }
  const db = c.get('db')
  const row = await updateTemplateTask(
    db,
    session.tid,
    c.req.param('id'),
    c.req.param('tid'),
    parsed.data,
  )
  if (!row) return c.json({ error: 'Not found or not editable' }, 404)
  return c.json(row, 200)
})

// ── DELETE /:id/tasks/:tid — remove template task ─────────────────────────────
projectTemplatesRoute.delete('/:id/tasks/:tid', requirePermission('projects:write'), 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 ok = await deleteTemplateTask(
    db,
    session.tid,
    c.req.param('id'),
    c.req.param('tid'),
  )
  if (!ok) return c.json({ error: 'Not found or not editable' }, 404)
  return c.json({ ok: true }, 200)
})

// ── POST /from-project/:projectId — save project as template ──────────────────
projectTemplatesRoute.post('/from-project/:projectId', requirePermission('projects:write'), 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 = saveAsTemplateSchema.safeParse(body)
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', issues: parsed.error.issues }, 400)
  }
  const db = c.get('db')
  const row = await saveProjectAsTemplate(
    db,
    session.tid,
    c.req.param('projectId'),
    parsed.data,
    session.sub,
  )
  return c.json(row, 201)
})

// ── POST /instantiate — create project from template ──────────────────────────
projectTemplatesRoute.post('/instantiate', requirePermission('projects:write'), 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 = instantiateTemplateSchema.safeParse(body)
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', issues: parsed.error.issues }, 400)
  }
  const db = c.get('db')
  try {
    const result = await instantiateTemplate(db, session.tid, parsed.data, session.sub)
    return c.json(result, 201)
  } catch (err) {
    const message = err instanceof Error ? err.message : 'Failed to instantiate template'
    return c.json({ error: message }, 422)
  }
})

export { projectTemplatesRoute }
