import express from 'express'
import { hasVisitorConsent } from './server/helpers.js'
import { isValidAdminSession } from './server/auth.js'
import { BACKUP_INTERVAL_MS } from './server/config.js'
import { state } from './server/state.js'
import {
  loadHitStatsFromDisk,
  loadVisitorStatsFromDisk,
  loadContactSubmissionsFromDisk,
  loadReplyTemplatesFromDisk,
  loadReplyHistoryFromDisk,
  loadQuestionsFromDisk,
  loadDraftQuestionsFromDisk,
  loadStudyUsersFromDisk,
  loadStudyCommunityFromDisk,
  loadStudyRemindersFromDisk,
  loadStudyCommentsFromDisk,
  loadStudyCertificatesFromDisk,
  loadEpisodeScriptsFromDisk,
  migrateStudyNotesIfNeeded,
  loadDownloadCountsFromDisk,
  loadQrCodesFromDisk,
  loadEpisodePlaysFromDisk,
  loadPodcastChecklistFromDisk,
  loadAnalyticsEventsFromDisk,
  loadEmailSettingsFromDisk,
  loadCalendarEventsFromDisk,
  loadAuditLogFromDisk,
  loadWebhooksFromDisk,
  createBackupSnapshot,
  refreshContentCaches,
  queueHitStatsWrite,
} from './server/data.js'
import { logResendEmailAlignmentWarnings, sendStudyReminderEmail, sendStudyReengagementEmail } from './server/email.js'
import {
  detectBot,
  sanitizeUserAgent,
  shouldCountHit,
  recordHit,
  scheduleStudyReminders,
  scheduleReengagementEmails,
} from './server/study-helpers.js'
import { recordVisitor } from './server/routes/analytics.js'

// Route registrars
import { register as registerAdminAuth } from './server/routes/admin-auth.js'
import { register as registerAdminContent } from './server/routes/admin-content.js'
import { register as registerAdminAssets } from './server/routes/admin-assets.js'
import { register as registerAdminBackup } from './server/routes/admin-backup.js'
import { register as registerStudyAuth } from './server/routes/study-auth.js'
import { register as registerStudyData } from './server/routes/study-data.js'
import { register as registerStudyAccount } from './server/routes/study-account.js'
import { register as registerStudyComments } from './server/routes/study-comments.js'
import { register as registerStudyCertificate } from './server/routes/study-certificate.js'
import { register as registerEpisodeScripts } from './server/routes/episode-scripts.js'
import { register as registerContact } from './server/routes/contact.js'
import { register as registerCalendarEvents } from './server/routes/calendar-events.js'
import { startReminderScheduler } from './server/reminder.js'
import { register as registerInboundEmail } from './server/routes/inbound-email.js'
import { register as registerQuestions } from './server/routes/questions.js'
import { register as registerAnalytics } from './server/routes/analytics.js'
import { register as registerDownloads } from './server/routes/downloads.js'
import { register as registerEpisodes } from './server/routes/episodes.js'
import { register as registerFeed } from './server/routes/feed.js'
import { register as registerQrCodes } from './server/routes/qr-codes.js'
import { register as registerBiblePassage } from './server/routes/bible-passage.js'
import { register as registerPublic } from './server/routes/public.js'

const app = express()
app.use(express.json({ limit: '10mb' }))
const trustProxyHops = Number(process.env.TRUST_PROXY_HOPS ?? 1)
app.set('trust proxy', Number.isFinite(trustProxyHops) && trustProxyHops >= 0 ? trustProxyHops : 1)

app.use((_req, res, next) => {
  res.setHeader('X-Content-Type-Options', 'nosniff')
  res.setHeader('X-Frame-Options', 'SAMEORIGIN')
  res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin')
  res.setHeader(
    'Content-Security-Policy',
    [
      "default-src 'self'",
      "script-src 'self' 'unsafe-inline' https://www.truthforlife.org https://ajax.googleapis.com",
      "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
      "font-src 'self' https://fonts.gstatic.com",
      "img-src 'self' data: https:",
      "media-src 'self' https:",
      "frame-src https:",
      "connect-src 'self' https:",
    ].join('; '),
  )
  next()
})

// Register API routes
registerAdminAuth(app)
registerAdminContent(app)
registerAdminAssets(app)
registerAdminBackup(app)
registerStudyAuth(app)
registerStudyData(app)
registerStudyAccount(app)
registerStudyComments(app)
registerStudyCertificate(app)
registerEpisodeScripts(app)
registerContact(app)
registerCalendarEvents(app)
registerInboundEmail(app)
registerQuestions(app)
registerAnalytics(app)
registerDownloads(app)
registerEpisodes(app)
registerFeed(app)
registerQrCodes(app)
registerBiblePassage(app)

// Hit-counting middleware (must come before public routes)
app.use((req, res, next) => {
  if (shouldCountHit(req)) {
    const ua = sanitizeUserAgent(req.get('user-agent'))
    const botDetection = detectBot(ua)
    recordHit(req.path, botDetection.isBot, botDetection.reason)
    queueHitStatsWrite()
    if (hasVisitorConsent(req) && !botDetection.isBot && !isValidAdminSession(req)) {
      recordVisitor(req, res).catch(err => {
        console.error('[visitor-stats] failed to record visitor:', err)
      })
    }
  }
  next()
})

// Public routes (robots, sitemap, static, SPA fallback)
registerPublic(app)

const PORT = Number(process.env.PORT ?? 4173)
Promise.all([
  loadHitStatsFromDisk(),
  loadVisitorStatsFromDisk(),
  loadContactSubmissionsFromDisk(),
  loadReplyTemplatesFromDisk(),
  loadReplyHistoryFromDisk(),
  loadQuestionsFromDisk(),
  loadDraftQuestionsFromDisk(),
  loadStudyUsersFromDisk(),
  loadStudyCommunityFromDisk(),
  loadStudyRemindersFromDisk(),
  loadStudyCommentsFromDisk(),
  loadStudyCertificatesFromDisk(),
  loadEpisodeScriptsFromDisk(),
  migrateStudyNotesIfNeeded(),
  loadDownloadCountsFromDisk(),
  loadQrCodesFromDisk(),
  loadEpisodePlaysFromDisk(),
  loadPodcastChecklistFromDisk(),
  loadAnalyticsEventsFromDisk(),
  loadEmailSettingsFromDisk(),
  loadCalendarEventsFromDisk(),
  loadAuditLogFromDisk(),
  loadWebhooksFromDisk(),
  refreshContentCaches(),
])
  .catch(err => {
    console.error('[stats] failed to load persisted stats:', err)
  })
  .finally(() => {
    createBackupSnapshot('startup').catch(() => {})
    setInterval(() => {
      createBackupSnapshot('scheduled').catch(() => {})
    }, BACKUP_INTERVAL_MS)

    startReminderScheduler()

    // Purge expired study sessions every hour
    setInterval(() => {
      const now = Date.now()
      for (const [token, session] of state.studySessions) {
        if (session.expiresAt <= now) state.studySessions.delete(token)
      }
    }, 60 * 60 * 1000)

    // Send study reminder emails for newly released lessons every hour
    setInterval(() => {
      scheduleStudyReminders(sendStudyReminderEmail).catch(err => {
        console.error('[study-reminders] failed to schedule reminders:', err)
      })
    }, 60 * 60 * 1000)
    void scheduleStudyReminders(sendStudyReminderEmail)

    // Send re-engagement emails to inactive study users every hour
    setInterval(() => {
      scheduleReengagementEmails(sendStudyReengagementEmail).catch(err => {
        console.error('[study-reengagement] failed to schedule emails:', err)
      })
    }, 60 * 60 * 1000)
    void scheduleReengagementEmails(sendStudyReengagementEmail)

    app.listen(PORT, () => {
      logResendEmailAlignmentWarnings()
      console.log(`Portfolio app listening on http://localhost:${PORT}`)
    })
  })
