import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { sanitizeSiteContent } from '../helpers.js'
import { requireAdminAuth, isValidAdminSession } from '../auth.js'
import {
  DATA_DIR,
  DATA_FILE,
  DRAFT_DATA_FILE,
  QUESTIONS_FILE,
  DEFAULT_SEO,
  DEFAULT_LEGAL,
  DEFAULT_REDIRECT_RULES,
  DEFAULT_PODCAST_FEATURED_LINKS,
  MAX_QUESTIONS,
  EMPTY_HIT_STATS,
  EMPTY_VISITOR_STATS,
} from '../config.js'
import { state } from '../state.js'
import {
  loadSiteContentFile,
  getStorageStatus,
  refreshContentCaches,
  queueHitStatsWrite,
  queueVisitorStatsWrite,
  queueContactSubmissionsWrite,
  queueReplyTemplatesWrite,
  queueReplyHistoryWrite,
  queuePodcastChecklistWrite,
  createBackupSnapshot,
  listBackupPreviews,
  readBackupPreview,
  restoreFromBackup,
  sanitizePodcastChecklist,
} from '../data.js'
import {
  pruneStatsByDays,
  filterSiteContentByReleaseDate,
} from '../study-helpers.js'

function invokeWebhook(url, action) {
  if (!url) {
    return Promise.resolve({ ok: false, message: `${action} webhook URL is not configured.` })
  }
  return fetch(url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ action, at: new Date().toISOString(), source: 'siteforge-admin' }),
  })
    .then(response => {
      if (!response.ok) return { ok: false, message: `${action} webhook failed with ${response.status}.` }
      return { ok: true, message: `${action} webhook triggered.` }
    })
    .catch(err => ({ ok: false, message: err instanceof Error ? err.message : `${action} webhook failed.` }))
}

export function register(app) {
  app.get('/api/admin-content', async (req, res) => {
    const source = req.query?.source === 'draft' ? 'draft' : 'published'
    if (source === 'draft' && !isValidAdminSession(req)) {
      res.status(401).json({ message: 'Unauthorized' })
      return
    }

    try {
      const parsed = await loadSiteContentFile(source === 'draft' ? DRAFT_DATA_FILE : DATA_FILE)
      if (source === 'published') {
        const safeSiteContent = filterSiteContentByReleaseDate(parsed.siteContent)
        res.json({ ...parsed, siteContent: safeSiteContent })
        return
      }
      res.json(parsed)
    } catch {
      if (source === 'draft') {
        res.status(404).json({ message: 'No saved draft content file yet.' })
        return
      }
      res.status(404).json({ message: 'No saved admin content file yet.' })
    }
  })

  app.get('/api/admin-content-state', requireAdminAuth, (_req, res) => {
    res.json({
      publishState: state.publishState,
      hasDraft: Boolean(state.cachedDraftSiteContent),
      hasPublished: Boolean(state.cachedSiteContent),
    })
  })

  app.get('/api/admin-storage-status', requireAdminAuth, async (_req, res) => {
    const status = await getStorageStatus()
    res.json(status)
  })

  app.get('/api/admin-podcast-checklist', requireAdminAuth, (_req, res) => {
    res.json({ checklist: state.podcastChecklist })
  })

  app.put('/api/admin-podcast-checklist', requireAdminAuth, async (req, res) => {
    try {
      const safeChecklist = sanitizePodcastChecklist(req.body?.checklist)
      state.podcastChecklist = safeChecklist
      await queuePodcastChecklistWrite()
      res.json({ ok: true, checklist: safeChecklist })
    } catch {
      res.status(500).json({ message: 'Failed to save podcast checklist.' })
    }
  })

  app.get('/api/site-config', async (_req, res) => {
    try {
      const parsed = await loadSiteContentFile(DATA_FILE)
      const siteContent = parsed.siteContent ?? {}
      res.json({
        seo: siteContent.seo ?? DEFAULT_SEO,
        legal: siteContent.legal ?? DEFAULT_LEGAL,
        redirects: siteContent.redirects ?? DEFAULT_REDIRECT_RULES,
        podcastFeaturedLinks: siteContent.podcastFeaturedLinks ?? DEFAULT_PODCAST_FEATURED_LINKS,
        publishState: state.publishState,
        updatedAt: parsed.updatedAt ?? null,
      })
    } catch {
      res.json({
        seo: DEFAULT_SEO,
        legal: DEFAULT_LEGAL,
        redirects: DEFAULT_REDIRECT_RULES,
        podcastFeaturedLinks: DEFAULT_PODCAST_FEATURED_LINKS,
        publishState: state.publishState,
        updatedAt: null,
      })
    }
  })

  app.put('/api/admin-content-draft', requireAdminAuth, async (req, res) => {
    try {
      const { siteContent } = req.body ?? {}

      if (!siteContent || typeof siteContent !== 'object' || Array.isArray(siteContent)) {
        res.status(400).json({ message: 'Invalid payload: siteContent must be an object.' })
        return
      }

      const safeSiteContent = sanitizeSiteContent(siteContent)
      const updatedAt = new Date().toISOString()

      await mkdir(DATA_DIR, { recursive: true })
      await writeFile(
        DRAFT_DATA_FILE,
        JSON.stringify({ siteContent: safeSiteContent, updatedAt }, null, 2),
        'utf8',
      )

      state.cachedDraftSiteContent = safeSiteContent
      state.publishState.draftUpdatedAt = updatedAt

      res.json({ ok: true, updatedAt })
    } catch (err) {
      console.error('[admin-content-draft] persist error:', err)
      const reason = err instanceof Error ? err.message : 'Unknown write error'
      res.status(500).json({ message: `Failed to persist admin draft content to ${DATA_DIR}: ${reason}` })
    }
  })

  app.post('/api/admin-content/publish', requireAdminAuth, async (_req, res) => {
    try {
      const source = state.cachedDraftSiteContent
        ? { siteContent: state.cachedDraftSiteContent, updatedAt: state.publishState.draftUpdatedAt ?? new Date().toISOString() }
        : await loadSiteContentFile(DRAFT_DATA_FILE)

      const publishedAt = new Date().toISOString()

      await mkdir(DATA_DIR, { recursive: true })
      await writeFile(
        DATA_FILE,
        JSON.stringify({ siteContent: source.siteContent, updatedAt: publishedAt }, null, 2),
        'utf8',
      )

      state.cachedSiteContent = source.siteContent
      state.publishState.publishedAt = publishedAt

      if (state.draftQuestions !== null) {
        state.questions = state.draftQuestions.slice(0, MAX_QUESTIONS)
        await mkdir(DATA_DIR, { recursive: true })
        await writeFile(
          QUESTIONS_FILE,
          JSON.stringify({ questions: state.questions, updatedAt: publishedAt }, null, 2),
          'utf8',
        )
      }

      await createBackupSnapshot('post-publish')
      res.json({ ok: true, publishedAt })
    } catch (err) {
      console.error('[admin-content-publish] persist error:', err)
      const reason = err instanceof Error ? err.message : 'Unknown write error'
      res.status(500).json({ message: `Failed to publish draft content to ${DATA_DIR}: ${reason}` })
    }
  })

  app.put('/api/admin-content', requireAdminAuth, async (req, res) => {
    try {
      const { siteContent } = req.body ?? {}

      if (!siteContent || typeof siteContent !== 'object' || Array.isArray(siteContent)) {
        res.status(400).json({ message: 'Invalid payload: siteContent must be an object.' })
        return
      }

      const safeSiteContent = sanitizeSiteContent(siteContent)
      const updatedAt = new Date().toISOString()

      await mkdir(DATA_DIR, { recursive: true })
      await writeFile(
        DATA_FILE,
        JSON.stringify({ siteContent: safeSiteContent, updatedAt }, null, 2),
        'utf8',
      )

      state.cachedSiteContent = safeSiteContent
      state.publishState.publishedAt = updatedAt

      res.json({ ok: true })
    } catch {
      res.status(500).json({ message: 'Failed to persist admin content.' })
    }
  })

  app.get('/api/admin-ops/status', requireAdminAuth, (_req, res) => {
    res.json({
      buildCommit: process.env.BUILD_COMMIT ?? null,
      buildNumber: process.env.BUILD_NUMBER ?? null,
      deployedAt: process.env.DEPLOYED_AT ?? null,
      cachePurge: state.lastCachePurgeStatus,
      deployHook: state.lastDeployHookStatus,
    })
  })

  app.post('/api/admin-ops/purge-cache', requireAdminAuth, async (_req, res) => {
    const result = await invokeWebhook(process.env.CACHE_PURGE_WEBHOOK_URL ?? '', 'cache-purge')
    state.lastCachePurgeStatus = { ok: result.ok, at: new Date().toISOString(), error: result.ok ? null : result.message }
    if (!result.ok) {
      res.status(400).json({ message: result.message })
      return
    }
    res.json({ ok: true, message: result.message })
  })

  app.post('/api/admin-ops/deploy', requireAdminAuth, async (_req, res) => {
    const result = await invokeWebhook(process.env.DEPLOY_WEBHOOK_URL ?? '', 'deploy')
    state.lastDeployHookStatus = { ok: result.ok, at: new Date().toISOString(), error: result.ok ? null : result.message }
    if (!result.ok) {
      res.status(400).json({ message: result.message })
      return
    }
    res.json({ ok: true, message: result.message })
  })

  app.get('/api/admin-stats/export', requireAdminAuth, async (_req, res) => {
    let adminContent = null
    let draftContent = null
    try {
      const raw = await readFile(DATA_FILE, 'utf8')
      adminContent = JSON.parse(raw)
    } catch { adminContent = null }

    try {
      const rawDraft = await readFile(DRAFT_DATA_FILE, 'utf8')
      draftContent = JSON.parse(rawDraft)
    } catch { draftContent = null }

    res.json({
      exportedAt: new Date().toISOString(),
      adminContent,
      draftContent,
      publishState: state.publishState,
      hitStats: state.hitStats,
      visitorStats: state.visitorStats,
      contactSubmissions: state.contactSubmissions,
      replyTemplates: state.replyTemplates,
      replyHistory: state.replyHistory,
    })
  })

  app.post('/api/admin-stats/clear', requireAdminAuth, (_req, res) => {
    state.hitStats = { ...EMPTY_HIT_STATS }
    state.visitorStats = { ...EMPTY_VISITOR_STATS }
    queueHitStatsWrite()
    queueVisitorStatsWrite()
    createBackupSnapshot('post-clear').catch(() => {})
    res.json({ ok: true })
  })

  app.post('/api/admin-stats/prune', requireAdminAuth, (req, res) => {
    const result = pruneStatsByDays(req.body?.days)
    queueHitStatsWrite()
    queueVisitorStatsWrite()
    createBackupSnapshot('post-prune').catch(() => {})
    res.json({ ok: true, ...result })
  })

  app.post('/api/admin-stats/backup', requireAdminAuth, async (_req, res) => {
    await createBackupSnapshot('manual')
    res.json({ ok: true, backup: state.lastBackupStatus })
  })

  app.get('/api/admin-stats/backups', requireAdminAuth, async (_req, res) => {
    try {
      const backups = await listBackupPreviews()
      res.json({ backups })
    } catch {
      res.status(500).json({ message: 'Could not list backups.' })
    }
  })

  app.post('/api/admin-stats/backup-preview', requireAdminAuth, async (req, res) => {
    try {
      const { filename } = req.body ?? {}
      const preview = await readBackupPreview(filename)
      res.json({ preview })
    } catch (err) {
      res.status(400).json({ message: err instanceof Error ? err.message : 'Could not load backup preview.' })
    }
  })

  app.post('/api/admin-stats/restore', requireAdminAuth, async (req, res) => {
    try {
      const { filename } = req.body ?? {}
      await restoreFromBackup(filename)
      const backups = await listBackupPreviews()
      res.json({ ok: true, restored: filename, backups })
    } catch (err) {
      res.status(400).json({ message: err instanceof Error ? err.message : 'Restore failed.' })
    }
  })
}
