const crypto = require('crypto');
const jwt    = require('jsonwebtoken');
const db     = require('../db/db');
const { JWT_SECRET } = require('../config');

/* ── Prepared statements ────────────────────────────────────────────── */
const stmts = {
  linkByToken:  db.prepare('SELECT * FROM parent_links WHERE token = ?'),
  linkById:     db.prepare('SELECT * FROM parent_links WHERE id = ?'),
  linksByStudent: db.prepare('SELECT id, token, label, is_active, last_used, created_at, expires_at FROM parent_links WHERE student_id = ? ORDER BY created_at DESC'),
  linkCount:    db.prepare('SELECT COUNT(*) AS cnt FROM parent_links WHERE student_id = ?'),
  insertLink:   db.prepare('INSERT INTO parent_links (student_id, token, label) VALUES (?, ?, ?)'),
  updateLink:   db.prepare('UPDATE parent_links SET label = ?, is_active = ? WHERE id = ?'),
  deleteLink:   db.prepare('DELETE FROM parent_links WHERE id = ?'),
  updateLastUsed: db.prepare("UPDATE parent_links SET last_used = datetime('now') WHERE id = ?"),

  /* Mega CTE: student info + stats + heatmap + weekly + recent activity in ONE query */
  dashboardMega: db.prepare(`
    WITH base AS (
      SELECT ts.id, ts.score, ts.total, ts.started_at, ts.finished_at,
             s.slug AS subject_slug, s.name AS subject_name
      FROM test_sessions ts
      LEFT JOIN subjects s ON s.id = ts.subject_id
      WHERE ts.user_id = @uid AND ts.status = 'completed'
    ),
    hm AS (
      SELECT date(ts.started_at) AS day, COUNT(*) AS cnt
      FROM test_sessions ts
      WHERE ts.user_id = @uid AND ts.started_at >= date('now', '-90 days')
      GROUP BY day ORDER BY day
    ),
    week_activity AS (
      SELECT COUNT(*) AS cnt,
             AVG(CASE WHEN total>0 THEN score*100.0/total END) AS avg_pct
      FROM base WHERE started_at >= date('now', 'weekday 0', '-7 days')
    )
    SELECT
      (SELECT json_object('name',u.name,'xp',u.xp,'level',u.level,
              'streak_current',u.streak_current,'streak_best',u.streak_best,'coins',u.coins)
       FROM users u WHERE u.id = @uid) AS student,
      (SELECT COALESCE(json_group_array(json_object(
         'week', week, 'sessions', sessions, 'avg_pct', avg_pct)), '[]')
       FROM (SELECT strftime('%Y-%W', finished_at) AS week,
                    COUNT(*) AS sessions,
                    AVG(CASE WHEN total>0 THEN score*100.0/total END) AS avg_pct
             FROM base WHERE finished_at >= date('now', '-56 days')
             GROUP BY week ORDER BY week)) AS weekly,
      (SELECT COALESCE(json_group_array(json_object('day', day, 'count', cnt)), '[]')
       FROM hm) AS heatmap,
      (SELECT COALESCE(json_group_array(json_object(
         'slug', subject_slug, 'name', subject_name,
         'sessions', sessions, 'avg_pct', avg_pct)), '[]')
       FROM (SELECT subject_slug, subject_name, COUNT(*) AS sessions,
                    AVG(CASE WHEN total>0 THEN score*100.0/total END) AS avg_pct
             FROM base GROUP BY subject_slug ORDER BY sessions DESC)) AS bySubject,
      (SELECT COALESCE(json_group_array(json_object(
         'id', id, 'score', score, 'total', total,
         'finished_at', finished_at, 'subject_slug', subject_slug)), '[]')
       FROM (SELECT id, score, total, finished_at, subject_slug
             FROM base ORDER BY finished_at ASC LIMIT 20)) AS trend,
      (SELECT json_object(
         'sessions', COUNT(*),
         'correct',  COALESCE(SUM(score), 0),
         'questions',COALESCE(SUM(total), 0),
         'avg_pct',  COALESCE(AVG(CASE WHEN total>0 THEN score*100.0/total END), 0))
       FROM base) AS totals,
      (SELECT MAX(started_at) FROM test_sessions WHERE user_id = @uid) AS lastSessionDate,
      (SELECT json_object('cnt', cnt, 'avg_pct', avg_pct) FROM week_activity) AS weekActivity
  `),

  weakTopics: db.prepare(`
    SELECT t.name AS topic, s.name AS subject_name,
           COUNT(ua.id) AS total,
           SUM(CASE WHEN ua.is_correct = 0 THEN 1 ELSE 0 END) AS wrong,
           ROUND(CAST(SUM(CASE WHEN ua.is_correct = 0 THEN 1 ELSE 0 END) AS REAL)
                 / COUNT(ua.id) * 100, 0) AS error_pct
    FROM user_answers ua
    JOIN test_sessions ts ON ts.id = ua.session_id
    JOIN questions q ON q.id = ua.question_id
    JOIN topics t ON t.id = q.topic_id
    JOIN subjects s ON s.id = q.subject_id
    WHERE ts.user_id = ? AND ts.status = 'completed' AND q.topic_id IS NOT NULL
    GROUP BY q.topic_id HAVING total >= 2
    ORDER BY error_pct DESC, wrong DESC LIMIT 5
  `),

  courseProgress: db.prepare(`
    SELECT c.id, c.title, c.cover_emoji, c.subject_slug,
           COUNT(l.id) AS total_lessons, COUNT(lp.id) AS done_lessons
    FROM courses c JOIN lessons l ON l.course_id = c.id AND l.is_published = 1
    LEFT JOIN lesson_progress lp ON lp.lesson_id = l.id AND lp.user_id = @uid
    WHERE c.is_published = 1 GROUP BY c.id HAVING done_lessons > 0
    ORDER BY done_lessons * 1.0 / total_lessons DESC LIMIT 10
  `),

  upcomingDeadlines: db.prepare(`
    SELECT a.id, a.title, a.deadline, a.subject_slug,
           (SELECT COUNT(*) FROM assignment_sessions ases
            JOIN test_sessions ts ON ts.id = ases.session_id
            WHERE ases.assignment_id = a.id AND ts.user_id = ? AND ts.status = 'completed') AS done
    FROM assignments a
    JOIN class_members cm ON cm.class_id = a.class_id AND cm.user_id = ?
    WHERE a.deadline IS NOT NULL AND a.deadline >= date('now', '-7 days')
    ORDER BY a.deadline ASC LIMIT 5
  `),

  recentSubmissions: db.prepare(`
    SELECT s.id, s.original_name, s.status, s.grade,
           s.submitted_at, a.title AS assignment_title
    FROM submissions s
    LEFT JOIN assignments a ON a.id = s.assignment_id
    WHERE s.student_id = ?
    ORDER BY s.submitted_at DESC LIMIT 10
  `),

  notifications: db.prepare(`
    SELECT id, type, message, is_read, created_at
    FROM parent_notifications WHERE parent_link_id = ?
    ORDER BY created_at DESC LIMIT 50
  `),
  markNotifRead: db.prepare('UPDATE parent_notifications SET is_read = 1 WHERE id = ? AND parent_link_id = ?'),
  unreadCount:   db.prepare('SELECT COUNT(*) AS cnt FROM parent_notifications WHERE parent_link_id = ? AND is_read = 0'),

  history: db.prepare(`
    SELECT ts.id, ts.mode, ts.score, ts.total, ts.status,
           ts.started_at, ts.finished_at,
           s.slug AS subject_slug, s.name AS subject_name
    FROM test_sessions ts
    LEFT JOIN subjects s ON s.id = ts.subject_id
    WHERE ts.user_id = ? AND ts.id < ?
    ORDER BY ts.id DESC LIMIT ?
  `),
  historyFirst: db.prepare(`
    SELECT ts.id, ts.mode, ts.score, ts.total, ts.status,
           ts.started_at, ts.finished_at,
           s.slug AS subject_slug, s.name AS subject_name
    FROM test_sessions ts
    LEFT JOIN subjects s ON s.id = ts.subject_id
    WHERE ts.user_id = ?
    ORDER BY ts.id DESC LIMIT ?
  `),
};

/* ══════════════════════════════════════════════════════════════════════
   STUDENT ENDPOINTS (regular authMiddleware)
   ══════════════════════════════════════════════════════════════════════ */

/* ── GET /api/parent/my-links ──────────────────────────────────────── */
function getMyLinks(req, res) {
  res.json(stmts.linksByStudent.all(req.user.id));
}

/* ── POST /api/parent/links ────────────────────────────────────────── */
function createLink(req, res) {
  const { cnt } = stmts.linkCount.get(req.user.id);
  if (cnt >= 3) return res.status(400).json({ error: 'Maximum 3 parent links allowed' });

  const label = (req.body.label || '').trim().slice(0, 50) || 'Родитель';
  const token = crypto.randomBytes(24).toString('hex');

  const r = stmts.insertLink.run(req.user.id, token, label);
  res.status(201).json({
    id: r.lastInsertRowid,
    token,
    label,
    url: `${req.protocol}://${req.get('host')}/parent?t=${token}`,
  });
}

/* ── PATCH /api/parent/links/:id ───────────────────────────────────── */
function updateLink(req, res) {
  const link = stmts.linkById.get(Number(req.params.id));
  if (!link || link.student_id !== req.user.id)
    return res.status(404).json({ error: 'Link not found' });

  const label     = req.body.label !== undefined ? String(req.body.label).trim().slice(0, 50) : link.label;
  const is_active = req.body.is_active !== undefined ? (req.body.is_active ? 1 : 0) : link.is_active;

  stmts.updateLink.run(label, is_active, link.id);
  res.json({ ok: true });
}

/* ── DELETE /api/parent/links/:id ──────────────────────────────────── */
function deleteLink(req, res) {
  const link = stmts.linkById.get(Number(req.params.id));
  if (!link || link.student_id !== req.user.id)
    return res.status(404).json({ error: 'Link not found' });

  stmts.deleteLink.run(link.id);
  res.json({ ok: true });
}

/* ══════════════════════════════════════════════════════════════════════
   PARENT ENDPOINTS (parentAuth middleware)
   ══════════════════════════════════════════════════════════════════════ */

/* ── POST /api/parent/auth — exchange link token for parent JWT ────── */
function exchangeToken(req, res) {
  const { token } = req.body;
  if (!token || typeof token !== 'string')
    return res.status(400).json({ error: 'token required' });

  const link = stmts.linkByToken.get(token);
  if (!link || !link.is_active)
    return res.status(404).json({ error: 'Link not found or deactivated' });
  if (link.expires_at && new Date(link.expires_at) < new Date())
    return res.status(410).json({ error: 'Link expired' });

  // Update last_used (only here, not on every request)
  try { stmts.updateLastUsed.run(link.id); } catch {}

  const parentJwt = jwt.sign(
    { type: 'parent', linkId: link.id, studentId: link.student_id },
    JWT_SECRET,
    { algorithm: 'HS256', expiresIn: '24h' }
  );

  // Inline student fetch (avoid importing studentBasic for this one-off)
  const student = db.prepare('SELECT name, level, streak_current FROM users WHERE id = ?').get(link.student_id);

  res.json({
    jwt: parentJwt,
    student: {
      name: student?.name,
      level: student?.level,
      streak_current: student?.streak_current,
    },
  });
}

/* ── GET /api/parent/dashboard — aggregated overview ─────────────────
   Optimized: 1 mega CTE + 3 focused queries = 4 total (was 9)
   ──────────────────────────────────────────────────────────────────── */
function getDashboard(req, res) {
  const uid = req.parent.studentId;

  // 1. Mega query: student + stats + heatmap + weekly + totals + recent activity
  const row = stmts.dashboardMega.get({ uid });
  const student = JSON.parse(row.student);
  if (!student) return res.status(404).json({ error: 'Student not found' });

  const weekly    = JSON.parse(row.weekly);
  const heatmap   = JSON.parse(row.heatmap);
  const bySubject = JSON.parse(row.bySubject);
  const trend     = JSON.parse(row.trend); // Already ASC from SQL
  const totals    = JSON.parse(row.totals);
  const weekAct   = JSON.parse(row.weekActivity);

  // 2. Weak topics (separate — heavy JOIN, can't merge into CTE)
  const weakTopics = stmts.weakTopics.all(uid);

  // 3. Deadlines + submissions (lightweight)
  const deadlines   = stmts.upcomingDeadlines.all(uid, uid);
  const submissions = stmts.recentSubmissions.all(uid);

  // 4. Course progress + unread notifs
  const courseProgress = stmts.courseProgress.all({ uid });
  const { cnt: unreadNotifs } = stmts.unreadCount.get(req.parent.linkId);

  // Alerts (computed in JS, zero DB cost)
  const alerts = [];
  if (row.lastSessionDate) {
    const daysSince = Math.floor((Date.now() - new Date(row.lastSessionDate).getTime()) / 86400000);
    if (daysSince >= 3) {
      alerts.push({ type: 'low_activity', icon: 'alert-triangle',
        message: `${student.name} не занимался ${daysSince} дней` });
    }
  }
  for (const d of deadlines) {
    if (d.done === 0 && new Date(d.deadline) < new Date()) {
      alerts.push({ type: 'deadline_missed', icon: 'clock',
        message: `Пропущен дедлайн: ${d.title}` });
    }
  }

  res.json({
    student,
    totals: {
      sessions:  totals.sessions  || 0,
      correct:   totals.correct   || 0,
      questions: totals.questions || 0,
      avgPct:    Math.round(totals.avg_pct || 0),
    },
    recentActivity: {
      lastSessionDate: row.lastSessionDate || null,
      sessionsThisWeek: weekAct?.cnt || 0,
      avgPctThisWeek: Math.round(weekAct?.avg_pct || 0),
    },
    weeklyStats: weekly.map(r => ({ week: r.week, sessions: r.sessions, avgPct: Math.round(r.avg_pct || 0) })),
    heatmap: heatmap.map(r => ({ day: r.day, count: r.count })),
    bySubject: bySubject.map(r => ({
      slug: r.slug, name: r.name, sessions: r.sessions,
      avgPct: Math.round(r.avg_pct || 0),
    })),
    trend: trend.map(r => ({
      pct: r.total > 0 ? Math.round(r.score * 100 / r.total) : 0,
      date: r.finished_at, subject: r.subject_slug,
    })),
    weakTopics: weakTopics.map(r => ({
      topic: r.topic, subject: r.subject_name, errorPct: r.error_pct,
    })),
    deadlines: deadlines.map(d => ({
      id: d.id, title: d.title, deadline: d.deadline,
      subject: d.subject_slug, done: d.done > 0,
    })),
    submissions: submissions.map(s => ({
      id: s.id, name: s.original_name, status: s.status,
      grade: s.grade, date: s.submitted_at, assignment: s.assignment_title,
    })),
    courseProgress: courseProgress.map(r => ({
      id: r.id, title: r.title, emoji: r.cover_emoji,
      done: r.done_lessons, total: r.total_lessons,
      pct: r.total_lessons > 0 ? Math.round(r.done_lessons * 100 / r.total_lessons) : 0,
    })),
    alerts,
    unreadNotifs,
  });
}

/* ── GET /api/parent/history ─────────────────────────────────────────── */
function getHistory(req, res) {
  const uid    = req.parent.studentId;
  const limit  = Math.min(50, Math.max(1, Number(req.query.limit) || 20));
  const cursor = Number(req.query.cursor) || 0;

  const rows = cursor
    ? stmts.history.all(uid, cursor, limit)
    : stmts.historyFirst.all(uid, limit);

  const nextCursor = rows.length === limit ? rows[rows.length - 1].id : null;
  res.json({ rows, nextCursor });
}

/* ── GET /api/parent/notifications ───────────────────────────────────── */
function getNotifications(req, res) {
  res.json(stmts.notifications.all(req.parent.linkId));
}

/* ── PATCH /api/parent/notifications/:id/read ────────────────────────── */
function markRead(req, res) {
  stmts.markNotifRead.run(Number(req.params.id), req.parent.linkId);
  res.json({ ok: true });
}

module.exports = {
  getMyLinks, createLink, updateLink, deleteLink,
  exchangeToken, getDashboard, getHistory, getNotifications, markRead,
};
