import { randomUUID } from 'node:crypto'
import rateLimit from 'express-rate-limit'
import { requireAdminAuth } from '../auth.js'
import { requireStudyAuth, normalizeStudySlug, isStudyUserEnrolled, getStudyTitleBySlug } from '../study-helpers.js'
import { state } from '../state.js'
import { loadUserProgress, queueStudyCertificatesWrite } from '../data.js'

const publicCertRateLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 30,
  standardHeaders: true,
  legacyHeaders: false,
  message: { message: 'Too many certificate lookups. Please wait a moment.' },
})

/**
 * Returns the list of required section IDs for a study (only released sections).
 */
function getRequiredSectionIds(studySlug) {
  const content = state.cachedSiteContent
  if (!content || !Array.isArray(content.studies)) return null
  const study = content.studies.find(s => s?.slug === studySlug)
  if (!study || !Array.isArray(study.sections)) return null
  return study.sections
    .filter(s => s?.status !== 'unreleased' && s?.id)
    .map(s => s.id)
}

export function register(app) {
  // GET — check eligibility and return existing certificate token if one exists
  app.get('/api/study-certificate/:studySlug', requireStudyAuth, async (req, res) => {
    const user = req.studyUser
    const studySlug = normalizeStudySlug(req.params.studySlug)
    if (!studySlug) { res.status(400).json({ message: 'Invalid study slug.' }); return }

    if (!isStudyUserEnrolled(user, studySlug)) {
      res.status(403).json({ message: 'Not enrolled in this study.' }); return
    }

    const requiredIds = getRequiredSectionIds(studySlug)
    if (!requiredIds || requiredIds.length === 0) {
      res.status(404).json({ message: 'Study sections not found.' }); return
    }

    const progress = await loadUserProgress(user.id)
    const completedIds = progress.byStudy[studySlug]?.completedSectionIds ?? []
    const eligible = requiredIds.every(id => completedIds.includes(id))

    const existing = state.studyCertificates.find(c => c.userId === user.id && c.studySlug === studySlug)

    res.json({
      eligible,
      studyTitle: getStudyTitleBySlug(studySlug) || studySlug,
      completedCount: completedIds.filter(id => requiredIds.includes(id)).length,
      totalCount: requiredIds.length,
      token: existing?.token ?? null,
      issuedAt: existing?.issuedAt ?? null,
    })
  })

  // POST — issue/re-issue a certificate (must be eligible)
  app.post('/api/study-certificate/:studySlug', requireStudyAuth, async (req, res) => {
    const user = req.studyUser
    const studySlug = normalizeStudySlug(req.params.studySlug)
    if (!studySlug) { res.status(400).json({ message: 'Invalid study slug.' }); return }

    if (!isStudyUserEnrolled(user, studySlug)) {
      res.status(403).json({ message: 'Not enrolled in this study.' }); return
    }

    const requiredIds = getRequiredSectionIds(studySlug)
    if (!requiredIds || requiredIds.length === 0) {
      res.status(404).json({ message: 'Study sections not found.' }); return
    }

    const progress = await loadUserProgress(user.id)
    const completedIds = progress.byStudy[studySlug]?.completedSectionIds ?? []
    const eligible = requiredIds.every(id => completedIds.includes(id))

    if (!eligible) {
      res.status(403).json({ message: 'Complete all sections to earn your certificate.' }); return
    }

    // Find or create
    let cert = state.studyCertificates.find(c => c.userId === user.id && c.studySlug === studySlug)
    if (!cert) {
      cert = {
        id: randomUUID(),
        token: randomUUID(),
        userId: user.id,
        studySlug,
        studyTitle: getStudyTitleBySlug(studySlug) || studySlug,
        displayName: user.displayName || user.username,
        issuedAt: new Date().toISOString(),
      }
      state.studyCertificates.push(cert)
      queueStudyCertificatesWrite()
    }

    res.json({ ok: true, token: cert.token, issuedAt: cert.issuedAt })
  })

  // GET — public certificate page data (no auth, by token)
  app.get('/api/public/certificate/:token', publicCertRateLimiter, (req, res) => {
    const { token } = req.params
    if (!token || typeof token !== 'string' || token.length > 100) {
      res.status(400).json({ message: 'Invalid token.' }); return
    }

    const cert = state.studyCertificates.find(c => c.token === token)
    if (!cert) { res.status(404).json({ message: 'Certificate not found.' }); return }

    res.json({
      studyTitle: cert.studyTitle,
      displayName: cert.displayName,
      issuedAt: cert.issuedAt,
    })
  })

  // Admin: list all certificates
  app.get('/api/admin-study-certificates', requireAdminAuth, (_req, res) => {
    res.json({ certificates: state.studyCertificates })
  })
}
