/**
 * Student Fees Helper Controller (§10c)
 *
 * GET /api/students/:uid/fees
 * GET /api/students/me/fees
 *
 * Returns a single-student fee profile that joins:
 *   - student_fees            line-level fee rows
 *   - fee_plan_installments   plan context (when the line came from a plan)
 *   - student_fee_discounts  applied discounts, with the discount's scope label
 *
 * Plus trip_payments rows for the same student, so a parent / student
 * portal can show everything in one fetch.
 *
 * RBAC: financeAccess for admin/bursar/accountant/principal/hr;
 * parent can fetch their child; student can fetch themselves.
 *
 * The `/me` shortcut resolves the student's public uid from the JWT
 * identity, so client code that only has the numeric user id (the
 * shape returned by /auth/login) can still fetch its own fees.
 */

const express = require('express');
const { v4: uuidv4 } = require('uuid');
const Database = require('better-sqlite3');
const path = require('path');
const AuditService = require('../services/AuditService');
const { outstandingForFee } = require('../lib/outstanding');

const db = new Database(process.env.DB_PATH || path.join(__dirname, '../../data/school.db'));
db.pragma('foreign_keys = ON');

const router = express.Router();

const auth = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: 'No token provided' });
  try {
    const jwt = require('jsonwebtoken');
    const { jwtSecret: JWT_SECRET } = require('../config');
    req.user = jwt.verify(token, JWT_SECRET);
    next();
  } catch (err) {
    return res.status(401).json({ error: 'Invalid token' });
  }
};

const privileged = ['school_admin', 'systems_admin', 'principal', 'bursar', 'accountant', 'hr'];

// Resolves the fee profile for a given student uid. The auth + RBAC
// checks live in the caller so /me/fees can short-circuit them with
// "you are the student".
const loadStudentFees = (student) => {
  const fees = db.prepare(`
    SELECT sf.*, fg.name AS fee_name, fg.type AS fee_type,
           p.id AS plan_id, p.name AS plan_name
    FROM student_fees sf
    LEFT JOIN fee_groups fg ON sf.fee_group_id = fg.id
    LEFT JOIN fee_plans p ON sf.plan_id = p.id
    WHERE sf.student_id = ? AND sf.is_deleted = 0
    ORDER BY sf.due_date ASC, sf.id ASC
  `).all(student.id);

  // Hydrate discounts per fee (one query per fee is fine at this scale).
  const discountsByFee = new Map();
  const feeIds = fees.map((f) => f.id);
  if (feeIds.length > 0) {
    const placeholders = feeIds.map(() => '?').join(',');
    const links = db.prepare(`
      SELECT sfd.student_fee_id, sfd.amount_applied, d.uid AS discount_uid, d.name AS discount_name,
             d.kind AS discount_kind, d.value AS discount_value, d.scope AS discount_scope
      FROM student_fee_discounts sfd
      JOIN discounts d ON sfd.discount_id = d.id
      WHERE sfd.is_deleted = 0 AND sfd.student_fee_id IN (${placeholders})
    `).all(...feeIds);
    for (const r of links) {
      if (!discountsByFee.has(r.student_fee_id)) discountsByFee.set(r.student_fee_id, []);
      discountsByFee.get(r.student_fee_id).push(r);
    }
  }

  const trips = db.prepare(`
    SELECT tp.*, t.name AS trip_name, t.departure_date, t.return_date, t.status AS trip_status
    FROM trip_payments tp
    JOIN trips t ON tp.trip_id = t.id
    WHERE tp.student_id = ? AND tp.is_deleted = 0
    ORDER BY t.departure_date DESC, tp.id DESC
  `).all(student.id);

  // Roll-ups
  const feesWithBalances = fees.map((f) => ({
    ...f,
    ...outstandingForFee(f),
    discounts: discountsByFee.get(f.id) || [],
  }));
  const outstanding = feesWithBalances.reduce((sum, fee) => sum + fee.outstanding, 0);
  const totalDiscount = fees.reduce((sum, f) => sum + (Number(f.discount_amount) || 0), 0);

  return {
    student,
    fees: feesWithBalances,
    trips,
    summary: {
      fees_count: fees.length,
      overdue_count: fees.filter((f) => f.due_date && new Date(f.due_date) < new Date() && !['paid', 'cancelled'].includes(f.status)).length,
      outstanding: Math.round(outstanding * 100) / 100,
      total_discount: Math.round(totalDiscount * 100) / 100,
      trips_count: trips.length,
      trips_outstanding: Math.round(trips.reduce((s, t) => s + (Number(t.invoiced_amount) || 0) - (Number(t.paid_amount) || 0), 0) * 100) / 100,
    },
  };
};

/**
 * GET /api/students/me/fees
 * Self-service shortcut for the student portal. Resolves the student
 * from the JWT identity so callers don't need to know their own uid.
 */
router.get('/me/fees', auth, async (req, res) => {
  try {
    if (req.user.role !== 'student') {
      return res.status(403).json({ error: 'Student access required' });
    }
    const student = db.prepare(
      'SELECT id, uid, first_name, last_name, email FROM users WHERE id = ? AND role = ? AND is_deleted = 0'
    ).get(req.user.id, 'student');
    if (!student) return res.status(404).json({ error: 'Student not found' });
    res.json(loadStudentFees(student));
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

router.get('/:uid/fees', auth, async (req, res) => {
  try {
    const student = db.prepare('SELECT id, uid, first_name, last_name, email FROM users WHERE uid = ? AND role = ? AND is_deleted = 0').get(req.params.uid, 'student');
    if (!student) return res.status(404).json({ error: 'Student not found' });

    // Privacy gate: parent can read their child, student can read self.
    // The original chained `if/else` was structurally broken — when a
    // student matched the student branch and fell through, control hit
    // the `else` of the parent check and returned 403 even for a student
    // accessing their own UID. Restructure as if/else-if so each role
    // takes its own branch.
    if (!privileged.includes(req.user.role)) {
      if (req.user.role === 'student') {
        if (Number(req.user.id) !== Number(student.id)) {
          return res.status(403).json({ error: 'You may only view your own fees' });
        }
      } else if (req.user.role === 'parent') {
        const linked = db.prepare(`
          SELECT 1 FROM parent_students WHERE parent_id = ? AND student_id = ? AND is_deleted = 0
        `).get(req.user.id, student.id);
        if (!linked) return res.status(403).json({ error: 'Not linked to this student' });
      } else {
        return res.status(403).json({ error: 'Forbidden' });
      }
    }

    res.json(loadStudentFees(student));
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

module.exports = router;
