const db   = require('../db/db');
const path = require('path');
const fs   = require('fs');
const { UPLOADS_DIR } = require('../config');

const { checkMagicBytes } = require('../utils/magic');

/* ── GET /api/files?subject=bio&my=1 ─────────────────────────────────── */
function listFiles(req, res) {
  const { subject, my } = req.query;
  const uid      = req.user.id;
  const isTeacher = ['teacher', 'admin'].includes(req.user.role);

  let sql, args;

  const cols = `f.id, f.title, f.description, f.original_name, f.mimetype, f.size,
             f.subject_slug, f.is_public, f.folder_id, f.created_at,
             u.name AS uploader_name`;

  if (isTeacher && my === '1') {
    sql = `SELECT ${cols} FROM files f JOIN users u ON u.id = f.uploaded_by WHERE f.uploaded_by = ?`;
    args = [uid];
  } else if (isTeacher) {
    sql = `SELECT ${cols} FROM files f JOIN users u ON u.id = f.uploaded_by WHERE (f.uploaded_by = ? OR f.is_public = 1)`;
    args = [uid];
  } else {
    sql = `
      SELECT DISTINCT ${cols}
      FROM files f JOIN users u ON u.id = f.uploaded_by
      WHERE (
        f.is_public = 1
        OR EXISTS (SELECT 1 FROM file_access fa WHERE fa.file_id = f.id AND fa.type = 'user' AND fa.target_id = ?)
        OR EXISTS (SELECT 1 FROM file_access fa JOIN class_members cm ON cm.class_id = fa.target_id AND cm.user_id = ? WHERE fa.file_id = f.id AND fa.type = 'class')
      )
    `;
    args = [uid, uid];
  }

  if (subject) { sql += ' AND f.subject_slug = ?'; args.push(subject); }
  sql += ' ORDER BY f.created_at DESC LIMIT 200';

  res.json(db.prepare(sql).all(...args));
}

/* ── GET /api/files/folders ──────────────────────────────────────────── */
function listFolders(req, res) {
  const uid = req.user.id;
  const isTeacher = ['teacher', 'admin'].includes(req.user.role);

  if (isTeacher) {
    const rows = db.prepare(`
      SELECT fo.id, fo.name, fo.created_by, fo.created_at,
             (SELECT COUNT(*) FROM files f WHERE f.folder_id = fo.id) AS file_count,
             (SELECT COUNT(*) FROM folder_access fa WHERE fa.folder_id = fo.id) AS access_count,
             u.name AS creator_name
      FROM folders fo JOIN users u ON u.id = fo.created_by
      ORDER BY fo.name ASC
    `).all();
    return res.json(rows);
  }

  // Students: only folders with no restrictions, or where they have explicit access
  const rows = db.prepare(`
    SELECT fo.id, fo.name, fo.created_by, fo.created_at,
           (SELECT COUNT(*) FROM files f WHERE f.folder_id = fo.id) AS file_count,
           0 AS access_count,
           u.name AS creator_name
    FROM folders fo JOIN users u ON u.id = fo.created_by
    WHERE (
      NOT EXISTS (SELECT 1 FROM folder_access fa WHERE fa.folder_id = fo.id)
      OR EXISTS (SELECT 1 FROM folder_access fa WHERE fa.folder_id = fo.id AND fa.type = 'user' AND fa.target_id = ?)
      OR EXISTS (
        SELECT 1 FROM folder_access fa
        JOIN class_members cm ON cm.class_id = fa.target_id AND cm.user_id = ?
        WHERE fa.folder_id = fo.id AND fa.type = 'class'
      )
    )
    ORDER BY fo.name ASC
  `).all(uid, uid);
  res.json(rows);
}

/* ── POST /api/files/folders ─────────────────────────────────────────── */
function createFolder(req, res) {
  const { name } = req.body;
  if (!name?.trim()) return res.status(400).json({ error: 'name required' });
  const r = db.prepare('INSERT INTO folders (name, created_by) VALUES (?, ?)').run(name.trim(), req.user.id);
  res.status(201).json({ id: r.lastInsertRowid, name: name.trim() });
}

/* ── PUT /api/files/folders/:id ──────────────────────────────────────── */
function renameFolder(req, res) {
  const fo = db.prepare('SELECT * FROM folders WHERE id = ?').get(req.params.id);
  if (!fo) return res.status(404).json({ error: 'Folder not found' });
  if (req.user.role !== 'admin' && fo.created_by !== req.user.id)
    return res.status(403).json({ error: 'Forbidden' });
  const { name } = req.body;
  if (!name?.trim()) return res.status(400).json({ error: 'name required' });
  db.prepare('UPDATE folders SET name = ? WHERE id = ?').run(name.trim(), fo.id);
  res.json({ ok: true });
}

/* ── DELETE /api/files/folders/:id ──────────────────────────────────── */
function deleteFolder(req, res) {
  const fo = db.prepare('SELECT * FROM folders WHERE id = ?').get(req.params.id);
  if (!fo) return res.status(404).json({ error: 'Folder not found' });
  if (req.user.role !== 'admin' && fo.created_by !== req.user.id)
    return res.status(403).json({ error: 'Forbidden' });
  // Move files back to root before deleting
  db.prepare('UPDATE files SET folder_id = NULL WHERE folder_id = ?').run(fo.id);
  db.prepare('DELETE FROM folders WHERE id = ?').run(fo.id);
  res.json({ ok: true });
}

/* ── PATCH /api/files/:id/move ───────────────────────────────────────── */
function moveFile(req, res) {
  const f = db.prepare('SELECT id, uploaded_by FROM files WHERE id = ?').get(req.params.id);
  if (!f) return res.status(404).json({ error: 'File not found' });
  if (req.user.role !== 'admin' && f.uploaded_by !== req.user.id)
    return res.status(403).json({ error: 'Forbidden' });
  const folderId = req.body.folder_id ? Number(req.body.folder_id) : null;
  if (folderId !== null) {
    const fo = db.prepare('SELECT id FROM folders WHERE id = ?').get(folderId);
    if (!fo) return res.status(404).json({ error: 'Folder not found' });
  }
  db.prepare('UPDATE files SET folder_id = ? WHERE id = ?').run(folderId, f.id);
  res.json({ ok: true });
}

/* ── POST /api/files ─────────────────────────────────────────────────── */
function uploadFile(req, res) {
  if (!req.file) return res.status(400).json({ error: 'No file uploaded' });
  const { title, description, subject_slug, is_public, folder_id } = req.body;
  if (!title?.trim()) return res.status(400).json({ error: 'title required' });

  // Magic bytes verification — reject files whose content doesn't match declared MIME
  const filePath = path.resolve(UPLOADS_DIR, req.file.filename);
  if (!checkMagicBytes(filePath, req.file.mimetype)) {
    try { fs.unlinkSync(filePath); } catch {}
    return res.status(400).json({ error: 'Содержимое файла не соответствует его расширению' });
  }

  let r;
  try {
    r = db.prepare(`
      INSERT INTO files (title, description, original_name, stored_name, mimetype, size, subject_slug, is_public, folder_id, uploaded_by)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `).run(
      title.trim(),
      description?.trim() || null,
      req.file.originalname,
      req.file.filename,
      req.file.mimetype,
      req.file.size,
      subject_slug || null,
      is_public === '0' ? 0 : 1,
      folder_id ? Number(folder_id) : null,
      req.user.id
    );
  } catch (err) {
    // Clean up orphan file if DB insert failed
    const fp = path.resolve(UPLOADS_DIR, req.file.filename);
    if (fp.startsWith(UPLOADS_DIR + path.sep)) { try { fs.unlinkSync(fp); } catch {} }
    throw err;
  }

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

/* ── GET /api/files/:id/download ─────────────────────────────────────── */
function downloadFile(req, res) {
  const f = db.prepare('SELECT * FROM files WHERE id = ?').get(req.params.id);
  if (!f) return res.status(404).json({ error: 'File not found' });

  const uid       = req.user.id;
  const isTeacher = ['teacher', 'admin'].includes(req.user.role);

  if (!f.is_public && !isTeacher && f.uploaded_by !== uid) {
    const hasAccess = db.prepare(`
      SELECT 1 FROM file_access fa
      WHERE fa.file_id = ? AND (
        (fa.type = 'user' AND fa.target_id = ?)
        OR (fa.type = 'class' AND EXISTS (
          SELECT 1 FROM class_members cm WHERE cm.class_id = fa.target_id AND cm.user_id = ?
        ))
      ) LIMIT 1
    `).get(f.id, uid, uid);
    if (!hasAccess) return res.status(403).json({ error: 'Access denied' });
  }

  const filePath = path.resolve(UPLOADS_DIR, f.stored_name);
  if (!filePath.startsWith(UPLOADS_DIR + path.sep) && filePath !== UPLOADS_DIR)
    return res.status(400).json({ error: 'Invalid file path' });
  if (!fs.existsSync(filePath)) return res.status(404).json({ error: 'File missing from storage' });

  const inlineSafe = /^(image\/(png|jpeg|gif|webp)|application\/pdf)$/.test(f.mimetype);
  const disposition = inlineSafe ? 'inline' : 'attachment';
  const encoded = encodeURIComponent(f.original_name);
  res.setHeader('Content-Disposition', `${disposition}; filename="${encoded}"; filename*=UTF-8''${encoded}`);
  res.setHeader('Content-Type', f.mimetype || 'application/octet-stream');
  res.sendFile(filePath);
}

/* ── DELETE /api/files/:id ───────────────────────────────────────────── */
function deleteFile(req, res) {
  const f = db.prepare('SELECT * FROM files WHERE id = ?').get(req.params.id);
  if (!f) return res.status(404).json({ error: 'File not found' });

  const isAdmin = req.user.role === 'admin';
  if (!isAdmin && f.uploaded_by !== req.user.id)
    return res.status(403).json({ error: 'Forbidden' });

  const filePath = path.resolve(UPLOADS_DIR, f.stored_name);
  if (filePath.startsWith(UPLOADS_DIR + path.sep)) { try { fs.unlinkSync(filePath); } catch {} }

  db.prepare('DELETE FROM files WHERE id = ?').run(req.params.id);
  res.json({ ok: true });
}

/* ── GET /api/files/:id/access ───────────────────────────────────────── */
function getFileAccess(req, res) {
  const f = db.prepare('SELECT id, uploaded_by FROM files WHERE id = ?').get(req.params.id);
  if (!f) return res.status(404).json({ error: 'File not found' });
  const isAdmin = req.user.role === 'admin';
  if (!isAdmin && f.uploaded_by !== req.user.id) return res.status(403).json({ error: 'Forbidden' });

  const rows = db.prepare(`
    SELECT fa.id, fa.type, fa.target_id,
      CASE fa.type
        WHEN 'class' THEN (SELECT name FROM classes WHERE id = fa.target_id)
        WHEN 'user'  THEN (SELECT name || ' (' || email || ')' FROM users WHERE id = fa.target_id)
      END AS target_name
    FROM file_access fa WHERE fa.file_id = ?
    ORDER BY fa.type, fa.id
  `).all(req.params.id);

  res.json(rows);
}

/* ── POST /api/files/:id/assign ──────────────────────────────────────── */
function assignFile(req, res) {
  const f = db.prepare('SELECT id, uploaded_by FROM files WHERE id = ?').get(req.params.id);
  if (!f) return res.status(404).json({ error: 'File not found' });
  const isAdmin = req.user.role === 'admin';
  if (!isAdmin && f.uploaded_by !== req.user.id) return res.status(403).json({ error: 'Forbidden' });

  const { type, target_id, email } = req.body;
  if (!['class', 'user'].includes(type)) return res.status(400).json({ error: 'type must be class or user' });

  let tid = Number(target_id);
  if (type === 'user' && email) {
    const u = db.prepare('SELECT id FROM users WHERE email = ?').get(email.trim().toLowerCase());
    if (!u) return res.status(404).json({ error: 'Пользователь не найден' });
    tid = u.id;
  }
  if (!tid) return res.status(400).json({ error: 'target_id required' });

  try {
    db.prepare('INSERT INTO file_access (file_id, type, target_id) VALUES (?, ?, ?)').run(f.id, type, tid);
  } catch (e) {
    if (e.message.includes('UNIQUE')) return res.status(409).json({ error: 'Уже назначен' });
    throw e;
  }
  res.json({ ok: true });
}

/* ── DELETE /api/files/:id/assign/:type/:targetId ────────────────────── */
function unassignFile(req, res) {
  const f = db.prepare('SELECT id, uploaded_by FROM files WHERE id = ?').get(req.params.id);
  if (!f) return res.status(404).json({ error: 'File not found' });
  const isAdmin = req.user.role === 'admin';
  if (!isAdmin && f.uploaded_by !== req.user.id) return res.status(403).json({ error: 'Forbidden' });

  db.prepare('DELETE FROM file_access WHERE file_id = ? AND type = ? AND target_id = ?')
    .run(f.id, req.params.type, Number(req.params.targetId));
  res.json({ ok: true });
}

/* ── GET /api/files/folders/:id/access ───────────────────────────────── */
function getFolderAccess(req, res) {
  const fo = db.prepare('SELECT id, created_by FROM folders WHERE id = ?').get(req.params.id);
  if (!fo) return res.status(404).json({ error: 'Folder not found' });

  const rows = db.prepare(`
    SELECT fa.id, fa.type, fa.target_id,
      CASE fa.type
        WHEN 'class' THEN (SELECT name FROM classes WHERE id = fa.target_id)
        WHEN 'user'  THEN (SELECT name || ' (' || email || ')' FROM users WHERE id = fa.target_id)
      END AS target_name
    FROM folder_access fa WHERE fa.folder_id = ?
    ORDER BY fa.type, fa.id
  `).all(fo.id);
  res.json(rows);
}

/* ── POST /api/files/folders/:id/assign ──────────────────────────────── */
function assignFolder(req, res) {
  const fo = db.prepare('SELECT id, created_by FROM folders WHERE id = ?').get(req.params.id);
  if (!fo) return res.status(404).json({ error: 'Folder not found' });
  if (req.user.role !== 'admin' && fo.created_by !== req.user.id)
    return res.status(403).json({ error: 'Forbidden' });

  const { type, target_id, email } = req.body;
  if (!['class', 'user'].includes(type)) return res.status(400).json({ error: 'type must be class or user' });

  let tid = Number(target_id);
  if (type === 'user' && email) {
    const u = db.prepare('SELECT id FROM users WHERE email = ?').get(email.trim().toLowerCase());
    if (!u) return res.status(404).json({ error: 'Пользователь не найден' });
    tid = u.id;
  }
  if (!tid) return res.status(400).json({ error: 'target_id required' });

  try {
    db.prepare('INSERT INTO folder_access (folder_id, type, target_id) VALUES (?, ?, ?)').run(fo.id, type, tid);
  } catch (e) {
    if (e.message.includes('UNIQUE')) return res.status(409).json({ error: 'Уже назначен' });
    throw e;
  }
  res.json({ ok: true });
}

/* ── DELETE /api/files/folders/:id/assign/:type/:targetId ────────────── */
function unassignFolder(req, res) {
  const fo = db.prepare('SELECT id, created_by FROM folders WHERE id = ?').get(req.params.id);
  if (!fo) return res.status(404).json({ error: 'Folder not found' });
  if (req.user.role !== 'admin' && fo.created_by !== req.user.id)
    return res.status(403).json({ error: 'Forbidden' });

  db.prepare('DELETE FROM folder_access WHERE folder_id = ? AND type = ? AND target_id = ?')
    .run(fo.id, req.params.type, Number(req.params.targetId));
  res.json({ ok: true });
}

/* ── DELETE /api/files/folders/:id/access (clear all) ───────────────── */
function clearFolderAccess(req, res) {
  const fo = db.prepare('SELECT id, created_by FROM folders WHERE id = ?').get(req.params.id);
  if (!fo) return res.status(404).json({ error: 'Folder not found' });
  if (req.user.role !== 'admin' && fo.created_by !== req.user.id)
    return res.status(403).json({ error: 'Forbidden' });

  db.prepare('DELETE FROM folder_access WHERE folder_id = ?').run(fo.id);
  res.json({ ok: true });
}

module.exports = { listFiles, uploadFile, downloadFile, deleteFile, getFileAccess, assignFile, unassignFile, listFolders, createFolder, renameFolder, deleteFolder, moveFile, getFolderAccess, assignFolder, unassignFolder, clearFolderAccess };
