// Pillars and lessons. Lesson bodies are gated behind an active membership,
// except lessons flagged is_free_preview. Metadata (titles, summaries) is open
// so the library is browsable before joining.
import { Router } from 'express';
import { ulid } from 'ulid';
import { query, queryOne, execute } from '../db/client.js';
import { optionalAuth, requireAuth } from '../middleware/auth.js';
import { getSubscriptionStatus } from '../middleware/subscription.js';
import { HttpError } from '../middleware/error.js';

const router = Router();
const now = () => Math.floor(Date.now() / 1000);

async function viewerIsActive(req) {
  if (!req.auth) return false;
  if (req.auth.role === 'admin') return true;
  return (await getSubscriptionStatus(req.auth.userId)).active;
}

// GET /api/content/pillars -> the four pillars with published lesson counts.
router.get('/pillars', async (_req, res, next) => {
  try {
    const pillars = await query(
      `SELECT id, slug, title, subtitle, kind, intro_video_url, sort FROM pillars
       ORDER BY CASE kind WHEN 'core' THEN 0 ELSE 1 END, sort ASC, created_at ASC`
    );
    const counts = await query(
      `SELECT pillar_id, COUNT(*) AS n FROM lessons WHERE published = 1 GROUP BY pillar_id`
    );
    const countMap = {};
    for (const c of counts) countMap[c.pillar_id] = Number(c.n);
    res.json({ pillars: pillars.map((p) => ({ ...p, lesson_count: countMap[p.id] || 0 })) });
  } catch (err) {
    next(err);
  }
});

// GET /api/content/lessons -> all published lesson metadata, with a locked flag per viewer.
router.get('/lessons', optionalAuth, async (req, res, next) => {
  try {
    const active = await viewerIsActive(req);
    const lessons = await query(
      `SELECT l.id, l.pillar_id, l.slug, l.title, l.summary, l.est_minutes, l.sort,
              l.is_free_preview, p.slug AS pillar_slug
       FROM lessons l JOIN pillars p ON p.id = l.pillar_id
       WHERE l.published = 1
       ORDER BY p.sort ASC, l.sort ASC`
    );
    res.json({
      viewer_active: active,
      lessons: lessons.map((l) => ({ ...l, locked: !(active || l.is_free_preview === 1) })),
    });
  } catch (err) {
    next(err);
  }
});

// GET /api/content/lessons/:slug -> full lesson. body_html only when unlocked.
router.get('/lessons/:slug', optionalAuth, async (req, res, next) => {
  try {
    const lesson = await queryOne(
      `SELECT l.*, p.slug AS pillar_slug, p.title AS pillar_title
       FROM lessons l JOIN pillars p ON p.id = l.pillar_id
       WHERE l.slug = ? AND l.published = 1`,
      [req.params.slug]
    );
    if (!lesson) throw new HttpError(404, 'not_found', 'Lesson not found');

    const active = await viewerIsActive(req);
    const canView = active || lesson.is_free_preview === 1;
    res.json({
      lesson: {
        id: lesson.id,
        slug: lesson.slug,
        title: lesson.title,
        summary: lesson.summary,
        est_minutes: lesson.est_minutes,
        pillar_slug: lesson.pillar_slug,
        pillar_title: lesson.pillar_title,
        is_free_preview: lesson.is_free_preview,
        locked: !canView,
        video_url: canView ? (lesson.video_url || null) : null,
        body_html: canView ? lesson.body_html : null,
      },
    });
  } catch (err) {
    next(err);
  }
});

// POST /api/content/lessons/:slug/complete -> mark a lesson complete for the member.
router.post('/lessons/:slug/complete', requireAuth, async (req, res, next) => {
  try {
    const lesson = await queryOne(`SELECT id FROM lessons WHERE slug = ?`, [req.params.slug]);
    if (!lesson) throw new HttpError(404, 'not_found', 'Lesson not found');
    await execute(
      `INSERT INTO lesson_progress (user_id, lesson_id, completed_at) VALUES (?, ?, ?)
       ON CONFLICT(user_id, lesson_id) DO UPDATE SET completed_at = excluded.completed_at`,
      [req.auth.userId, lesson.id, now()]
    );
    res.json({ ok: true });
  } catch (err) {
    next(err);
  }
});

// GET /api/content/progress -> slugs of lessons this member has completed.
// Powers the front-end progress rings, XP, and badges.
router.get('/progress', requireAuth, async (req, res, next) => {
  try {
    const rows = await query(
      `SELECT l.slug AS slug, lp.completed_at AS completed_at
       FROM lesson_progress lp
       JOIN lessons l ON l.id = lp.lesson_id
       WHERE lp.user_id = ? AND lp.completed_at IS NOT NULL`,
      [req.auth.userId]
    );
    res.json({ completed: rows.map((r) => r.slug), count: rows.length });
  } catch (err) {
    next(err);
  }
});

// GET /api/content/lessons/:slug/quiz -> the quiz for a lesson, WITHOUT correct answers.
// Returns { quiz: null } if the lesson has no quiz. Gated like lesson bodies.
router.get('/lessons/:slug/quiz', optionalAuth, async (req, res, next) => {
  try {
    const lesson = await queryOne(`SELECT id FROM lessons WHERE slug = ? AND published = 1`, [req.params.slug]);
    if (!lesson) throw new HttpError(404, 'not_found', 'Lesson not found');
    const quiz = await queryOne(`SELECT pass_pct, question_count, questions FROM quizzes WHERE lesson_id = ?`, [lesson.id]);
    if (!quiz) { res.json({ quiz: null }); return; }
    const active = await viewerIsActive(req);
    if (!active) {
      res.json({ quiz: { locked: true, pass_pct: quiz.pass_pct, question_count: quiz.question_count } });
      return;
    }
    // Strip correct answers and explanations before sending to the client.
    const questions = JSON.parse(quiz.questions || '[]').map((q, i) => ({ i, q: q.q, options: q.options || [] }));
    res.json({ quiz: { locked: false, pass_pct: quiz.pass_pct, question_count: quiz.question_count, questions } });
  } catch (err) {
    next(err);
  }
});

// POST /api/content/lessons/:slug/quiz/submit  { answers: [optionIndex, ...] }
// Grades server-side, records the attempt, and on >= pass_pct marks the lesson complete.
router.post('/lessons/:slug/quiz/submit', requireAuth, async (req, res, next) => {
  try {
    const lesson = await queryOne(`SELECT id FROM lessons WHERE slug = ? AND published = 1`, [req.params.slug]);
    if (!lesson) throw new HttpError(404, 'not_found', 'Lesson not found');
    const active = req.auth.role === 'admin' || (await getSubscriptionStatus(req.auth.userId)).active;
    if (!active) throw new HttpError(403, 'subscription_required', 'Active membership required');
    const quiz = await queryOne(`SELECT pass_pct, questions FROM quizzes WHERE lesson_id = ?`, [lesson.id]);
    if (!quiz) throw new HttpError(404, 'not_found', 'No quiz for this lesson');

    const questions = JSON.parse(quiz.questions || '[]');
    const answers = Array.isArray(req.body && req.body.answers) ? req.body.answers : [];
    let score = 0;
    const results = questions.map((q, i) => {
      const your = Number.isInteger(answers[i]) ? answers[i] : -1;
      const ok = your === q.correct;
      if (ok) score += 1;
      return { i, correct: q.correct, your, ok, explanation: q.explanation || null };
    });
    const total = questions.length;
    const passed = total > 0 && Math.round((score / total) * 100) >= quiz.pass_pct;

    await execute(
      `INSERT INTO quiz_attempts (id, user_id, lesson_id, score, total, passed, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [ulid(), req.auth.userId, lesson.id, score, total, passed ? 1 : 0, now()]
    );
    if (passed) {
      await execute(
        `INSERT INTO lesson_progress (user_id, lesson_id, completed_at) VALUES (?, ?, ?)
         ON CONFLICT(user_id, lesson_id) DO UPDATE SET completed_at = excluded.completed_at`,
        [req.auth.userId, lesson.id, now()]
      );
    }
    res.json({ score, total, passed, pass_pct: quiz.pass_pct, results });
  } catch (err) {
    next(err);
  }
});

// GET /api/content/lessons/:slug/resources -> rebuilt-on-brand resources for a lesson.
// Body HTML only when the viewer is active (gated like lesson bodies).
router.get('/lessons/:slug/resources', optionalAuth, async (req, res, next) => {
  try {
    const lesson = await queryOne(`SELECT id FROM lessons WHERE slug = ? AND published = 1`, [req.params.slug]);
    if (!lesson) throw new HttpError(404, 'not_found', 'Lesson not found');
    const rows = await query(
      `SELECT id, sort, type, title, body_html FROM lesson_resources WHERE lesson_id = ? ORDER BY sort ASC`,
      [lesson.id]
    );
    if (!rows.length) { res.json({ resources: [] }); return; }
    const active = await viewerIsActive(req);
    // Members fill resources in directly on the site; load their saved answers in one shot.
    const respMap = {};
    if (active && req.auth) {
      const saved = await query(
        `SELECT resource_id, data FROM resource_responses WHERE user_id = ?`,
        [req.auth.userId]
      );
      for (const s of saved) respMap[s.resource_id] = s.data;
    }
    const parse = (s) => { try { return JSON.parse(s || '{}'); } catch { return {}; } };
    res.json({
      resources: rows.map((r) => ({
        id: r.id,
        type: r.type,
        title: r.title,
        locked: !active,
        body_html: active ? r.body_html : null,
        response: active ? parse(respMap[r.id]) : null,
      })),
    });
  } catch (err) {
    next(err);
  }
});

// POST /api/content/resources/:id/response  { data: { fieldKey: value, ... } }
// Saves a member's filled-in answers for one resource to their account. Members
// work the workbooks/tools in place; nothing is downloaded, the work stays here.
router.post('/resources/:id/response', requireAuth, async (req, res, next) => {
  try {
    const active = req.auth.role === 'admin' || (await getSubscriptionStatus(req.auth.userId)).active;
    if (!active) throw new HttpError(403, 'subscription_required', 'Active membership required');
    const resource = await queryOne(`SELECT id FROM lesson_resources WHERE id = ?`, [req.params.id]);
    if (!resource) throw new HttpError(404, 'not_found', 'Resource not found');
    const payload = req.body && typeof req.body.data === 'object' && req.body.data ? req.body.data : {};
    await execute(
      `INSERT INTO resource_responses (user_id, resource_id, data, updated_at) VALUES (?, ?, ?, ?)
       ON CONFLICT(user_id, resource_id) DO UPDATE SET data = excluded.data, updated_at = excluded.updated_at`,
      [req.auth.userId, resource.id, JSON.stringify(payload), now()]
    );
    res.json({ ok: true });
  } catch (err) {
    next(err);
  }
});

export default router;
