import { Router } from 'express';
import { db } from '../db/index.js';
import { santri, kelas, angkatan, users } from '../db/schema.js';
import { eq, and, asc } from 'drizzle-orm';
import multer from 'multer';
import { parse } from 'csv-parse/sync';
import { stringify } from 'csv-stringify/sync';
import { requireAuth, requireAdmin } from '../middleware/auth.js';
import { encrypt, decrypt } from '../lib/crypto.js';
import { makeSlug, uniqueSlug } from '../lib/slug.js';
import { normalizeWa, isValidWa } from '../lib/wa.js';
import { logAudit } from '../lib/audit.js';

const router = Router();
const memUpload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 5 * 1024 * 1024 } });

router.use(requireAuth);

// Helper: cek kalau wali kelas, batasi ke kelasnya
async function userCanAccessKelas(user, kelasId) {
  if (user.role === 'admin') return true;
  const [k] = await db.select().from(kelas).where(eq(kelas.id, kelasId)).limit(1);
  return k && k.waliKelasUserId === user.id;
}

// LIST per kelas
router.get('/kelas/:kelasId', async (req, res) => {
  const kelasId = Number(req.params.kelasId);
  if (!(await userCanAccessKelas(req.user, kelasId))) {
    return res.status(403).render('error', { title: 'Forbidden', message: 'Akses ditolak.' });
  }
  const [k] = await db.select().from(kelas).where(eq(kelas.id, kelasId)).limit(1);
  if (!k) return res.status(404).render('error', { title: 'Not Found', message: 'Kelas tidak ditemukan.' });
  const [a] = await db.select().from(angkatan).where(eq(angkatan.id, k.angkatanId)).limit(1);

  const rows = await db.select().from(santri).where(eq(santri.kelasId, kelasId)).orderBy(asc(santri.nama));
  const list = rows.map((r) => ({ ...r, nomorWa: decrypt(r.nomorWaEnc) }));

  const total = list.length;
  const terkirim = list.filter((r) => r.statusTerkirim).length;

  res.render('santri/index', {
    title: `Santri ${k.nama}`,
    kelas: k,
    angkatan: a,
    santriList: list,
    total,
    terkirim,
    canEdit: req.user.role === 'admin' || req.user.role === 'wali_kelas',
  });
});

// FORM tambah (admin only)
router.get('/new', requireAdmin, async (req, res) => {
  const kelasList = await db
    .select({ id: kelas.id, nama: kelas.nama, angkatanId: kelas.angkatanId, angkatanNomor: angkatan.nomor })
    .from(kelas)
    .leftJoin(angkatan, eq(kelas.angkatanId, angkatan.id))
    .orderBy(asc(angkatan.nomor), asc(kelas.nama));
  res.render('santri/form', { title: 'Tambah Santri', item: null, kelasList });
});

router.post('/', requireAdmin, async (req, res) => {
  const { kelasId, nis, nama, nomorWa } = req.body;
  const [k] = await db.select().from(kelas).where(eq(kelas.id, Number(kelasId))).limit(1);
  if (!k) return res.status(400).render('error', { title: 'Bad Request', message: 'Kelas tidak valid.' });

  if (!isValidWa(nomorWa)) {
    req.flash('error', 'Nomor WA tidak valid.');
    return res.redirect('/santri/new');
  }

  const baseSlug = makeSlug(nama);
  const slug = await uniqueSlug(baseSlug, async (cand) => {
    const found = await db
      .select()
      .from(santri)
      .where(and(eq(santri.angkatanId, k.angkatanId), eq(santri.slug, cand)))
      .limit(1);
    return found.length > 0;
  });

  await db.insert(santri).values({
    kelasId: k.id,
    angkatanId: k.angkatanId,
    nis,
    nama,
    slug,
    nomorWaEnc: encrypt(normalizeWa(nomorWa)),
  });
  await logAudit({ userId: req.user.id, action: 'santri.create', entityType: 'santri', metadata: { nama, kelasId } });
  req.flash('success', `Santri ${nama} ditambahkan.`);
  res.redirect(`/santri/kelas/${k.id}`);
});

// EDIT — admin: full, wali kelas: hanya nomor WA
router.get('/:id/edit', async (req, res) => {
  const id = Number(req.params.id);
  const [item] = await db.select().from(santri).where(eq(santri.id, id)).limit(1);
  if (!item) return res.status(404).render('error', { title: 'Not Found', message: 'Santri tidak ditemukan.' });
  if (!(await userCanAccessKelas(req.user, item.kelasId))) {
    return res.status(403).render('error', { title: 'Forbidden', message: 'Akses ditolak.' });
  }
  const kelasList = await db
    .select({ id: kelas.id, nama: kelas.nama, angkatanId: kelas.angkatanId, angkatanNomor: angkatan.nomor })
    .from(kelas)
    .leftJoin(angkatan, eq(kelas.angkatanId, angkatan.id))
    .orderBy(asc(angkatan.nomor), asc(kelas.nama));

  res.render('santri/form', {
    title: 'Edit Santri',
    item: { ...item, nomorWa: decrypt(item.nomorWaEnc) },
    kelasList,
    isWaliOnly: req.user.role !== 'admin',
  });
});

router.put('/:id', async (req, res) => {
  const id = Number(req.params.id);
  const [item] = await db.select().from(santri).where(eq(santri.id, id)).limit(1);
  if (!item) return res.status(404).render('error', { title: 'Not Found', message: 'Santri tidak ditemukan.' });
  if (!(await userCanAccessKelas(req.user, item.kelasId))) {
    return res.status(403).render('error', { title: 'Forbidden', message: 'Akses ditolak.' });
  }

  const { nomorWa } = req.body;
  if (!isValidWa(nomorWa)) {
    req.flash('error', 'Nomor WA tidak valid.');
    return res.redirect(`/santri/${id}/edit`);
  }

  if (req.user.role === 'admin') {
    const { nis, nama, kelasId } = req.body;
    const newKelasId = Number(kelasId);
    const [newK] = await db.select().from(kelas).where(eq(kelas.id, newKelasId)).limit(1);
    if (!newK) return res.status(400).render('error', { title: 'Bad Request', message: 'Kelas tidak valid.' });

    let slug = item.slug;
    if (nama !== item.nama || newK.angkatanId !== item.angkatanId) {
      const baseSlug = makeSlug(nama);
      slug = await uniqueSlug(baseSlug, async (cand) => {
        if (cand === item.slug && newK.angkatanId === item.angkatanId) return false;
        const found = await db
          .select()
          .from(santri)
          .where(and(eq(santri.angkatanId, newK.angkatanId), eq(santri.slug, cand)))
          .limit(1);
        return found.length > 0;
      });
    }

    await db
      .update(santri)
      .set({
        kelasId: newK.id,
        angkatanId: newK.angkatanId,
        nis,
        nama,
        slug,
        nomorWaEnc: encrypt(normalizeWa(nomorWa)),
      })
      .where(eq(santri.id, id));
    await logAudit({ userId: req.user.id, action: 'santri.update', entityType: 'santri', entityId: id });
    req.flash('success', 'Data santri diperbarui.');
    return res.redirect(`/santri/kelas/${newK.id}`);
  }

  // Wali kelas: hanya nomor WA
  await db
    .update(santri)
    .set({ nomorWaEnc: encrypt(normalizeWa(nomorWa)) })
    .where(eq(santri.id, id));
  await logAudit({ userId: req.user.id, action: 'santri.update_wa', entityType: 'santri', entityId: id });
  req.flash('success', 'Nomor WA diperbarui.');
  res.redirect(`/santri/kelas/${item.kelasId}`);
});

router.delete('/:id', requireAdmin, async (req, res) => {
  const id = Number(req.params.id);
  const [item] = await db.select().from(santri).where(eq(santri.id, id)).limit(1);
  if (!item) return res.status(404).end();
  await db.delete(santri).where(eq(santri.id, id));
  await logAudit({ userId: req.user.id, action: 'santri.delete', entityType: 'santri', entityId: id });
  req.flash('success', 'Santri dihapus.');
  res.redirect(`/santri/kelas/${item.kelasId}`);
});

// =============== BULK IMPORT ===============
// Download template CSV
router.get('/template.csv', requireAdmin, (req, res) => {
  const csv = stringify(
    [
      ['nis', 'nama', 'kelas', 'nomor_wa'],
      ['22001', 'Contoh Santri', 'XII IPA 1', '08123456789'],
    ],
  );
  res.setHeader('Content-Type', 'text/csv; charset=utf-8');
  res.setHeader('Content-Disposition', 'attachment; filename="template_santri.csv"');
  res.send(csv);
});

// Halaman import per angkatan
router.get('/import/:angkatanId', requireAdmin, async (req, res) => {
  const angkatanId = Number(req.params.angkatanId);
  const [a] = await db.select().from(angkatan).where(eq(angkatan.id, angkatanId)).limit(1);
  if (!a) return res.status(404).render('error', { title: 'Not Found', message: 'Angkatan tidak ditemukan.' });
  const kelasList = await db.select().from(kelas).where(eq(kelas.angkatanId, angkatanId)).orderBy(asc(kelas.nama));
  res.render('santri/import', { title: `Import Santri Angkatan ${a.nomor}`, angkatanItem: a, kelasList });
});

router.post('/import/:angkatanId', requireAdmin, memUpload.single('file'), async (req, res) => {
  const angkatanId = Number(req.params.angkatanId);
  if (!req.file) {
    req.flash('error', 'File CSV wajib diunggah.');
    return res.redirect(`/santri/import/${angkatanId}`);
  }

  let records;
  try {
    records = parse(req.file.buffer, { columns: true, skip_empty_lines: true, trim: true });
  } catch (err) {
    req.flash('error', `Format CSV tidak valid: ${err.message}`);
    return res.redirect(`/santri/import/${angkatanId}`);
  }

  const kelasRows = await db.select().from(kelas).where(eq(kelas.angkatanId, angkatanId));
  const kelasByName = new Map(kelasRows.map((k) => [k.nama.toLowerCase(), k]));

  const errors = [];
  let success = 0;

  for (let i = 0; i < records.length; i++) {
    const row = records[i];
    const nis = String(row.nis || '').trim();
    const nama = String(row.nama || '').trim();
    const kelasNama = String(row.kelas || '').trim();
    const wa = String(row.nomor_wa || row.nomorWa || row.nomor || '').trim();

    if (!nis || !nama || !kelasNama || !wa) {
      errors.push(`Baris ${i + 2}: data tidak lengkap.`);
      continue;
    }
    const k = kelasByName.get(kelasNama.toLowerCase());
    if (!k) {
      errors.push(`Baris ${i + 2}: kelas "${kelasNama}" tidak ditemukan di angkatan ini.`);
      continue;
    }
    if (!isValidWa(wa)) {
      errors.push(`Baris ${i + 2}: nomor WA "${wa}" tidak valid.`);
      continue;
    }

    // cek NIS unik per angkatan
    const dup = await db
      .select()
      .from(santri)
      .where(and(eq(santri.angkatanId, angkatanId), eq(santri.nis, nis)))
      .limit(1);
    if (dup.length > 0) {
      errors.push(`Baris ${i + 2}: NIS ${nis} sudah ada di angkatan ini.`);
      continue;
    }

    const baseSlug = makeSlug(nama);
    const slug = await uniqueSlug(baseSlug, async (cand) => {
      const found = await db
        .select()
        .from(santri)
        .where(and(eq(santri.angkatanId, angkatanId), eq(santri.slug, cand)))
        .limit(1);
      return found.length > 0;
    });

    await db.insert(santri).values({
      kelasId: k.id,
      angkatanId,
      nis,
      nama,
      slug,
      nomorWaEnc: encrypt(normalizeWa(wa)),
    });
    success++;
  }

  await logAudit({
    userId: req.user.id,
    action: 'santri.bulk_import',
    entityType: 'angkatan',
    entityId: angkatanId,
    metadata: { success, errors: errors.length },
  });

  if (errors.length > 0) {
    req.flash('error', `Import sebagian. Sukses: ${success}. Gagal: ${errors.length}. ${errors.slice(0, 5).join(' | ')}${errors.length > 5 ? ' …' : ''}`);
  } else {
    req.flash('success', `Import berhasil: ${success} santri ditambahkan.`);
  }
  res.redirect(`/santri/import/${angkatanId}`);
});

export default router;
