const db = require('../db/db');

/* ── helpers ──────────────────────────────────────────────────────────── */

// Reused SQL fragment: user's completed-lesson count for a course (param: user_id)
const DONE_COUNT_SUBQ = `(SELECT COUNT(*) FROM lesson_progress lp
  JOIN lessons l2 ON lp.lesson_id = l2.id
  WHERE l2.course_id = c.id AND lp.user_id = ? AND lp.completed = 1) AS done_count`;

function courseRow(row) {
  return {
    id:          row.id,
    subjectSlug: row.subject_slug,
    title:       row.title,
    description: row.description || '',
    coverEmoji:  row.cover_emoji,
    orderIndex:  row.order_index,
    isPublished: row.is_published === 1,
    createdBy:   row.created_by,
    createdAt:   row.created_at,
    lessonCount: row.lesson_count ?? 0,
    doneCount:   row.done_count   ?? 0,
  };
}

function progressSubquery(role) {
  return role === 'student' ? 'AND l.is_published = 1' : '';
}

/* ── GET /api/courses ─────────────────────────────────────────────────── */
function list(req, res) {
  const { subject } = req.query;
  const role = req.user.role;
  const uid  = req.user.id;

  let where = role === 'student' ? 'WHERE c.is_published = 1' : 'WHERE 1=1';
  const args = [];
  if (subject) { where += ' AND c.subject_slug = ?'; args.push(subject); }

  const rows = db.prepare(`
    SELECT c.*,
      (SELECT COUNT(*) FROM lessons l WHERE l.course_id = c.id ${progressSubquery(role)}) AS lesson_count,
      ${DONE_COUNT_SUBQ}
    FROM courses c ${where}
    ORDER BY c.subject_slug, c.order_index, c.id
  `).all(uid, ...args);

  res.json(rows.map(courseRow));
}

/* ── GET /api/courses/search?q=… ─────────────────────────────────────── */
function search(req, res) {
  const q    = (req.query.q || '').trim();
  const role = req.user.role;
  const uid  = req.user.id;
  if (!q) return res.json({ courses: [], lessons: [] });

  const like = `%${q}%`;
  const pubC = role === 'student' ? 'AND c.is_published = 1' : '';
  const pubL = role === 'student' ? 'AND l.is_published = 1 AND c.is_published = 1' : '';

  const courses = db.prepare(`
    SELECT c.*,
      (SELECT COUNT(*) FROM lessons l WHERE l.course_id = c.id ${progressSubquery(role)}) AS lesson_count,
      ${DONE_COUNT_SUBQ}
    FROM courses c WHERE (c.title LIKE ? OR c.description LIKE ?) ${pubC}
    ORDER BY c.subject_slug, c.order_index LIMIT 20
  `).all(uid, like, like).map(courseRow);

  const lessons = db.prepare(`
    SELECT l.id, l.title, l.course_id, c.title AS course_title, c.subject_slug,
      lp.completed
    FROM lessons l
    JOIN courses c ON l.course_id = c.id
    LEFT JOIN lesson_progress lp ON lp.lesson_id = l.id AND lp.user_id = ?
    WHERE l.title LIKE ? ${pubL}
    ORDER BY c.subject_slug, l.order_index LIMIT 30
  `).all(uid, like);

  res.json({ courses, lessons });
}

/* ── GET /api/courses/continue ───────────────────────────────────────── */
// Returns the last-in-progress lesson across all courses
function continueLesson(req, res) {
  const uid  = req.user.id;
  const role = req.user.role;
  const pub  = role === 'student' ? 'AND l.is_published = 1 AND c.is_published = 1' : '';

  // 1. last started but not finished lesson (progress row exists, completed=0)
  let row = db.prepare(`
    SELECT l.id, l.title, l.course_id, c.title AS course_title, c.subject_slug, c.cover_emoji
    FROM lesson_progress lp
    JOIN lessons l ON lp.lesson_id = l.id
    JOIN courses c ON l.course_id = c.id
    WHERE lp.user_id = ? AND lp.completed = 0 ${pub}
    ORDER BY lp.updated_at DESC LIMIT 1
  `).get(uid);

  // 2. fallback: first unprogressed lesson in courses that have any progress
  if (!row) {
    row = db.prepare(`
      SELECT l.id, l.title, l.course_id, c.title AS course_title, c.subject_slug, c.cover_emoji
      FROM lessons l
      JOIN courses c ON l.course_id = c.id
      WHERE c.id IN (
        SELECT DISTINCT l2.course_id FROM lesson_progress lp2
        JOIN lessons l2 ON lp2.lesson_id = l2.id WHERE lp2.user_id = ?
      )
      AND l.id NOT IN (SELECT lesson_id FROM lesson_progress WHERE user_id = ?)
      ${pub}
      ORDER BY l.course_id, l.order_index LIMIT 1
    `).get(uid, uid);
  }

  res.json(row ? {
    lessonId:    row.id,
    lessonTitle: row.title,
    courseId:    row.course_id,
    courseTitle: row.course_title,
    subjectSlug: row.subject_slug,
    coverEmoji:  row.cover_emoji,
  } : null);
}

/* ── GET /api/courses/:id ─────────────────────────────────────────────── */
function get(req, res) {
  const role = req.user.role;
  const uid  = req.user.id;

  const row = db.prepare(`
    SELECT c.*,
      (SELECT COUNT(*) FROM lessons l WHERE l.course_id = c.id ${progressSubquery(role)}) AS lesson_count,
      ${DONE_COUNT_SUBQ}
    FROM courses c WHERE c.id = ?
  `).get(uid, req.params.id);

  if (!row) return res.status(404).json({ error: 'Course not found' });
  if (role === 'student' && !row.is_published)
    return res.status(403).json({ error: 'Course not published' });

  // sections
  const sections = db.prepare(
    'SELECT * FROM course_sections WHERE course_id = ? ORDER BY order_index, id'
  ).all(row.id);

  // lessons grouped
  const pubWhere = role === 'student' ? 'AND l.is_published = 1' : '';
  const lessons = db.prepare(`
    SELECT l.id, l.title, l.order_index, l.is_published, l.section_id, l.read_time,
      lp.completed
    FROM lessons l
    LEFT JOIN lesson_progress lp ON lp.lesson_id = l.id AND lp.user_id = ?
    WHERE l.course_id = ? ${pubWhere}
    ORDER BY l.order_index, l.id
  `).all(uid, row.id);

  res.json({
    ...courseRow(row),
    sections: sections.map(s => ({ id: s.id, title: s.title, orderIndex: s.order_index })),
    lessons:  lessons.map(l => ({
      id:          l.id,
      title:       l.title,
      orderIndex:  l.order_index,
      isPublished: l.is_published === 1,
      sectionId:   l.section_id,
      readTime:    l.read_time || 0,
      completed:   l.completed === 1,
    })),
  });
}

/* ── GET /api/courses/:id/stats?classId=X ────────────────────────────── */
function stats(req, res) {
  const { classId } = req.query;
  const course = db.prepare('SELECT id FROM courses WHERE id = ?').get(req.params.id);
  if (!course) return res.status(404).json({ error: 'Course not found' });

  // students in class (or all students who have progress)
  let members;
  if (classId) {
    members = db.prepare(`
      SELECT u.id FROM class_members cm JOIN users u ON cm.user_id = u.id
      WHERE cm.class_id = ? AND u.role = 'student'
    `).all(classId).map(r => r.id);
  } else {
    members = db.prepare(`
      SELECT DISTINCT lp.user_id AS id FROM lesson_progress lp
      JOIN lessons l ON lp.lesson_id = l.id WHERE l.course_id = ?
    `).all(course.id).map(r => r.id);
  }
  const total = members.length || 1;

  const lessons = db.prepare(`
    SELECT l.id, l.title, l.order_index,
      (SELECT COUNT(*) FROM lesson_progress lp
        WHERE lp.lesson_id = l.id AND lp.completed = 1
        AND lp.user_id IN (${members.map(() => '?').join(',') || 'NULL'})) AS done_count
    FROM lessons l WHERE l.course_id = ? ORDER BY l.order_index, l.id
  `).all(...members, course.id);

  res.json({ total, lessons: lessons.map(l => ({
    id: l.id, title: l.title,
    doneCount: l.done_count,
    pct: Math.round(l.done_count / total * 100),
  }))});
}

/* ── GET /api/courses/:id/analytics?classId=X ───────────────────────── */
function analytics(req, res) {
  const { classId } = req.query;
  const course = db.prepare('SELECT id, title FROM courses WHERE id = ?').get(req.params.id);
  if (!course) return res.status(404).json({ error: 'Course not found' });

  // all lessons in course
  const lessons = db.prepare(
    'SELECT id, title, order_index FROM lessons WHERE course_id = ? ORDER BY order_index, id'
  ).all(course.id);
  const lessonIds = lessons.map(l => l.id);
  const totalLessons = lessonIds.length;

  // students
  let students;
  if (classId) {
    students = db.prepare(`
      SELECT u.id, u.name, u.email FROM class_members cm
      JOIN users u ON cm.user_id = u.id
      WHERE cm.class_id = ? AND u.role = 'student'
      ORDER BY u.name
    `).all(classId);
  } else {
    students = db.prepare(`
      SELECT DISTINCT u.id, u.name, u.email FROM lesson_progress lp
      JOIN lessons l ON lp.lesson_id = l.id
      JOIN users u ON lp.user_id = u.id
      WHERE l.course_id = ?
      ORDER BY u.name
    `).all(course.id);
  }

  if (!students.length) {
    return res.json({
      totalStudents: 0, totalLessons, avgPct: 0,
      lessons: lessons.map(l => ({ id: l.id, title: l.title, doneCount: 0, pct: 0 })),
      students: [], stuckStudents: [],
    });
  }

  // Batch-fetch ALL progress for ALL students in ONE query (eliminates N+1)
  const studentIds = students.map(s => s.id);
  const lpRows = lessonIds.length && studentIds.length
    ? db.prepare(`
        SELECT user_id, lesson_id, completed, updated_at FROM lesson_progress
        WHERE user_id IN (${studentIds.map(() => '?').join(',')})
          AND lesson_id IN (${lessonIds.map(() => '?').join(',')})
      `).all(...studentIds, ...lessonIds)
    : [];

  // Index progress by [user_id][lesson_id]
  const progressByUser = {};
  for (const r of lpRows) {
    if (!progressByUser[r.user_id]) progressByUser[r.user_id] = {};
    progressByUser[r.user_id][r.lesson_id] = r;
  }

  // Per-lesson done count from the same data
  const lessonDoneCount = {};
  for (const lid of lessonIds) lessonDoneCount[lid] = 0;
  for (const r of lpRows) {
    if (r.completed === 1) lessonDoneCount[r.lesson_id] = (lessonDoneCount[r.lesson_id] || 0) + 1;
  }

  const studentData = students.map(s => {
    const progressMap = progressByUser[s.id] || {};
    const progress = Object.values(progressMap);
    const doneCnt = progress.filter(p => p.completed === 1).length;
    const pct = totalLessons > 0 ? Math.round(doneCnt / totalLessons * 100) : 0;

    // find first incomplete lesson
    let firstIncompleteIdx = -1;
    for (let i = 0; i < lessons.length; i++) {
      const p = progressMap[lessons[i].id];
      if (!p || p.completed !== 1) { firstIncompleteIdx = i; break; }
    }

    // "stuck" = started course (done > 0), not finished, and last activity > 3 days ago
    let stuck = false;
    let stuckLesson = null;
    let lastActivity = null;
    if (doneCnt > 0 && doneCnt < totalLessons) {
      const dates = progress.map(p => p.updated_at).filter(Boolean);
      if (dates.length) {
        lastActivity = dates.sort().pop();
        const daysSince = (Date.now() - new Date(lastActivity.replace(' ', 'T') + 'Z').getTime()) / 86400000;
        if (daysSince > 3) {
          stuck = true;
          stuckLesson = firstIncompleteIdx >= 0 ? lessons[firstIncompleteIdx] : null;
        }
      }
    }

    return {
      id: s.id, name: s.name, email: s.email,
      doneCount: doneCnt, pct, stuck,
      stuckLessonId: stuckLesson?.id || null,
      stuckLessonTitle: stuckLesson?.title || null,
      lastActivity,
    };
  });

  // Per-lesson stats from pre-computed counts (no extra queries)
  const lessonStats = lessons.map(l => {
    const doneCount = lessonDoneCount[l.id] || 0;
    return {
      id: l.id, title: l.title,
      doneCount,
      pct: students.length > 0 ? Math.round(doneCount / students.length * 100) : 0,
    };
  });

  const avgPct = studentData.length > 0
    ? Math.round(studentData.reduce((s, d) => s + d.pct, 0) / studentData.length)
    : 0;

  res.json({
    totalStudents: students.length,
    totalLessons,
    avgPct,
    lessons: lessonStats,
    students: studentData,
    stuckStudents: studentData.filter(s => s.stuck),
  });
}

/* ── POST /api/courses ────────────────────────────────────────────────── */
function create(req, res) {
  const { subjectSlug, title, description, coverEmoji, orderIndex } = req.body;
  if (!subjectSlug || !title)
    return res.status(400).json({ error: 'subjectSlug and title required' });

  const result = db.prepare(`
    INSERT INTO courses (subject_slug, title, description, cover_emoji, order_index, created_by)
    VALUES (?, ?, ?, ?, ?, ?)
  `).run(subjectSlug, title.trim(), description || null, coverEmoji || '', orderIndex ?? 0, req.user.id);
  res.status(201).json({ id: result.lastInsertRowid });
}

/* ── POST /api/courses/:id/duplicate ─────────────────────────────────── */
function duplicate(req, res) {
  const src = db.prepare('SELECT * FROM courses WHERE id = ?').get(req.params.id);
  if (!src) return res.status(404).json({ error: 'Course not found' });

  let newCourseId;
  db.transaction(() => {
    const cr = db.prepare(`
      INSERT INTO courses (subject_slug, title, description, cover_emoji, order_index, is_published, created_by)
      VALUES (?, ?, ?, ?, ?, 0, ?)
    `).run(src.subject_slug, src.title + ' (копия)', src.description, src.cover_emoji, src.order_index, req.user.id);
    newCourseId = cr.lastInsertRowid;

    // duplicate sections
    const secMap = {};
    const sections = db.prepare('SELECT * FROM course_sections WHERE course_id = ? ORDER BY order_index').all(src.id);
    for (const s of sections) {
      const sr = db.prepare('INSERT INTO course_sections (course_id, title, order_index) VALUES (?, ?, ?)').run(newCourseId, s.title, s.order_index);
      secMap[s.id] = sr.lastInsertRowid;
    }

    // duplicate lessons + blocks
    const lessons = db.prepare('SELECT * FROM lessons WHERE course_id = ? ORDER BY order_index').all(src.id);
    for (const l of lessons) {
      const lr = db.prepare(`
        INSERT INTO lessons (course_id, title, order_index, section_id, read_time)
        VALUES (?, ?, ?, ?, ?)
      `).run(newCourseId, l.title, l.order_index, l.section_id ? (secMap[l.section_id] || null) : null, l.read_time || 0);
      const newLid = lr.lastInsertRowid;

      const blocks = db.prepare('SELECT * FROM lesson_blocks WHERE lesson_id = ? ORDER BY order_index').all(l.id);
      for (const b of blocks) {
        db.prepare('INSERT INTO lesson_blocks (lesson_id, type, order_index, data) VALUES (?, ?, ?, ?)').run(newLid, b.type, b.order_index, b.data);
      }
    }
  })();

  res.status(201).json({ id: newCourseId });
}

/* ── PUT /api/courses/:id ─────────────────────────────────────────────── */
function update(req, res) {
  const row = db.prepare('SELECT * FROM courses WHERE id = ?').get(req.params.id);
  if (!row) return res.status(404).json({ error: 'Course not found' });
  const { title, description, coverEmoji, orderIndex, isPublished, subjectSlug } = req.body;

  db.prepare(`
    UPDATE courses SET title=?,description=?,cover_emoji=?,order_index=?,is_published=?,subject_slug=? WHERE id=?
  `).run(
    title       ?? row.title,
    description !== undefined ? description : row.description,
    coverEmoji  ?? row.cover_emoji,
    orderIndex  ?? row.order_index,
    isPublished !== undefined ? (isPublished ? 1 : 0) : row.is_published,
    subjectSlug ?? row.subject_slug,
    row.id
  );
  res.json({ ok: true });
}

/* ── DELETE /api/courses/:id ──────────────────────────────────────────── */
function remove(req, res) {
  const row = db.prepare('SELECT id FROM courses WHERE id = ?').get(req.params.id);
  if (!row) return res.status(404).json({ error: 'Course not found' });
  db.prepare('DELETE FROM courses WHERE id = ?').run(row.id);
  res.json({ ok: true });
}

/* ── SECTIONS ─────────────────────────────────────────────────────────── */
function listSections(req, res) {
  const rows = db.prepare('SELECT * FROM course_sections WHERE course_id = ? ORDER BY order_index, id').all(req.params.id);
  res.json(rows.map(s => ({ id: s.id, title: s.title, orderIndex: s.order_index })));
}

function createSection(req, res) {
  const course = db.prepare('SELECT id FROM courses WHERE id = ?').get(req.params.id);
  if (!course) return res.status(404).json({ error: 'Course not found' });
  const { title, orderIndex } = req.body;
  if (!title) return res.status(400).json({ error: 'title required' });
  const r = db.prepare('INSERT INTO course_sections (course_id, title, order_index) VALUES (?, ?, ?)').run(course.id, title.trim(), orderIndex ?? 0);
  res.status(201).json({ id: r.lastInsertRowid });
}

function updateSection(req, res) {
  const s = db.prepare('SELECT * FROM course_sections WHERE id = ? AND course_id = ?').get(req.params.sid, req.params.id);
  if (!s) return res.status(404).json({ error: 'Section not found' });
  const { title, orderIndex } = req.body;
  db.prepare('UPDATE course_sections SET title=?, order_index=? WHERE id=?').run(title ?? s.title, orderIndex ?? s.order_index, s.id);
  res.json({ ok: true });
}

function deleteSection(req, res) {
  const s = db.prepare('SELECT id FROM course_sections WHERE id = ? AND course_id = ?').get(req.params.sid, req.params.id);
  if (!s) return res.status(404).json({ error: 'Section not found' });
  // unlink lessons
  db.prepare('UPDATE lessons SET section_id = NULL WHERE section_id = ?').run(s.id);
  db.prepare('DELETE FROM course_sections WHERE id = ?').run(s.id);
  res.json({ ok: true });
}

/* ── CLASS COURSES ────────────────────────────────────────────────────── */
function listClassCourses(req, res) {
  const uid  = req.user.id;
  const role = req.user.role;
  const pub  = role === 'student' ? 'AND c.is_published = 1' : '';
  const rows = db.prepare(`
    SELECT c.*,
      (SELECT COUNT(*) FROM lessons l WHERE l.course_id = c.id ${progressSubquery(role)}) AS lesson_count,
      ${DONE_COUNT_SUBQ},
      cc.deadline
    FROM class_courses cc
    JOIN courses c ON cc.course_id = c.id
    WHERE cc.class_id = ? ${pub}
    ORDER BY cc.assigned_at
  `).all(uid, req.params.classId);
  res.json(rows.map(r => ({ ...courseRow(r), deadline: r.deadline })));
}

function assignCourseToClass(req, res) {
  const { classId } = req.params;
  const { courseId, deadline } = req.body;
  if (!courseId) return res.status(400).json({ error: 'courseId required' });
  try {
    db.prepare(`
      INSERT INTO class_courses (class_id, course_id, deadline, assigned_by)
      VALUES (?, ?, ?, ?)
      ON CONFLICT (class_id, course_id) DO UPDATE SET deadline=excluded.deadline
    `).run(classId, courseId, deadline || null, req.user.id);
    res.json({ ok: true });
  } catch (e) { console.error('[course assign]', e.message); res.status(400).json({ error: 'Ошибка назначения курса' }); }
}

function unassignCourseFromClass(req, res) {
  db.prepare('DELETE FROM class_courses WHERE class_id = ? AND course_id = ?').run(req.params.classId, req.params.courseId);
  res.json({ ok: true });
}

/* ── PATCH /api/courses/:id/publish-all ──────────────────────────────── */
function publishAll(req, res) {
  const course = db.prepare('SELECT id, created_by FROM courses WHERE id = ?').get(req.params.id);
  if (!course) return res.status(404).json({ error: 'Course not found' });
  if (req.user.role !== 'admin' && course.created_by !== req.user.id)
    return res.status(403).json({ error: 'Forbidden' });

  const publish = req.body.publish !== false; // default: publish=true
  const { changes } = db.prepare(
    'UPDATE lessons SET is_published = ? WHERE course_id = ?'
  ).run(publish ? 1 : 0, course.id);

  // Also publish/unpublish the course itself
  db.prepare('UPDATE courses SET is_published = ? WHERE id = ?').run(publish ? 1 : 0, course.id);

  res.json({ ok: true, lessonsUpdated: changes });
}

module.exports = {
  list, search, continueLesson, get, stats, analytics, create, duplicate, update, remove,
  listSections, createSection, updateSection, deleteSection,
  listClassCourses, assignCourseToClass, unassignCourseFromClass,
  publishAll,
};
