/**
 * Users Controller
 * CRUD operations with role-based filtering
 */

const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const { v4: uuidv4 } = require('uuid');

// Database path (shared with index.js)
const dbPath = process.env.DB_PATH || require('path').join(__dirname, '../../data/school.db');
const Database = require('better-sqlite3');
let db;

const getDb = () => {
  if (!db) {
    db = new Database(dbPath);
    db.pragma('foreign_keys = ON');
  }
  return db;
};

// Auth middleware
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 JWT_SECRET = process.env.JWT_SECRET || 'africa-alert-secret-key-2024';
    req.user = jwt.verify(token, JWT_SECRET);
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
};

// Admin-only middleware (includes principal)
const adminOnly = (req, res, next) => {
  if (req.user.role !== 'admin' && req.user.role !== 'principal') {
    return res.status(403).json({ error: 'Admin or Principal access required' });
  }
  next();
};

// ============ USERS CRUD ============

// List users with optional role filtering
router.get('/', auth, (req, res) => {
  try {
    const { role, search, status, department_id, page = 1, limit = 50 } = req.query;
    const offset = (page - 1) * limit;
    
    let query = `
      SELECT id, uid, email, role, first_name, last_name, phone, address, 
             gender, date_of_birth, profile_image, emergency_contact, emergency_phone,
             department_id, is_active, created_at, last_login
      FROM users
      WHERE is_deleted = 0
    `;
    const params = [];
    
    if (role) {
      query += ' AND role = ?';
      params.push(role);
    }
    
    if (department_id) {
      query += ' AND department_id = ?';
      params.push(department_id);
    }
    
    if (search) {
      query += ' AND (first_name LIKE ? OR last_name LIKE ? OR email LIKE ?)';
      const searchTerm = `%${search}%`;
      params.push(searchTerm, searchTerm, searchTerm);
    }
    
    if (status) {
      query += ' AND is_active = ?';
      params.push(status === 'active' ? 1 : 0);
    }
    
    query += ' ORDER BY last_name, first_name LIMIT ? OFFSET ?';
    params.push(parseInt(limit), parseInt(offset));
    
    const users = getDb().prepare(query).all(...params);
    
    // Get total count
    let countQuery = 'SELECT COUNT(*) as count FROM users WHERE is_deleted = 0';
    const countParams = [];
    if (role) {
      countQuery += ' AND role = ?';
      countParams.push(role);
    }
    if (department_id) {
      countQuery += ' AND department_id = ?';
      countParams.push(department_id);
    }
    if (search) {
      countQuery += ' AND (first_name LIKE ? OR last_name LIKE ? OR email LIKE ?)';
      const searchTerm = `%${search}%`;
      countParams.push(searchTerm, searchTerm, searchTerm);
    }
    const total = getDb().prepare(countQuery).all(...countParams)[0].count;
    
    res.json({
      users,
      pagination: {
        page: parseInt(page),
        limit: parseInt(limit),
        total,
        pages: Math.ceil(total / limit)
      }
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Get single user by ID
router.get('/:id', auth, (req, res) => {
  try {
    const user = getDb().prepare(`
      SELECT id, uid, email, role, first_name, last_name, phone, address,
             gender, date_of_birth, profile_image, emergency_contact, emergency_phone,
             department_id, is_active, created_at, last_login
      FROM users
      WHERE id = ? AND is_deleted = 0
    `).get(req.params.id);
    
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    res.json(user);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Get user by UID
router.get('/uid/:uid', auth, (req, res) => {
  try {
    const user = getDb().prepare(`
      SELECT id, uid, email, role, first_name, last_name, phone, address,
             gender, date_of_birth, profile_image, emergency_contact, emergency_phone,
             department_id, is_active, created_at, last_login
      FROM users
      WHERE uid = ? AND is_deleted = 0
    `).get(req.params.uid);
    
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    res.json(user);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Create new user
router.post('/', auth, adminOnly, (req, res) => {
  try {
    const { email, password, role, first_name, last_name, phone, address, gender, date_of_birth, emergency_contact, emergency_phone, department_id } = req.body;
    
    // Validate required fields
    if (!email || !password || !role || !first_name || !last_name) {
      return res.status(400).json({ error: 'Missing required fields: email, password, role, first_name, last_name' });
    }
    
    // Validate role
    const validRoles = ['admin', 'teacher', 'student', 'parent', 'accountant', 'librarian', 'nurse', 'principal', 'hr', 'bursar'];
    if (!validRoles.includes(role)) {
      return res.status(400).json({ error: `Invalid role. Must be one of: ${validRoles.join(', ')}` });
    }
    
    const hashedPassword = bcrypt.hashSync(password, 10);
    const uid = uuidv4();
    
    const result = getDb().prepare(`
      INSERT INTO users (uid, email, password, role, first_name, last_name, phone, address, gender, date_of_birth, emergency_contact, emergency_phone, department_id)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `).run(uid, email, hashedPassword, role, first_name, last_name, phone, address, gender, date_of_birth, emergency_contact, emergency_phone, department_id);
    
    const newUser = getDb().prepare('SELECT id, uid, email, role, first_name, last_name, phone, is_active, created_at FROM users WHERE id = ?').get(result.lastInsertRowid);
    
    res.status(201).json(newUser);
  } catch (error) {
    if (error.message.includes('UNIQUE constraint failed')) {
      return res.status(400).json({ error: 'Email already exists' });
    }
    res.status(500).json({ error: error.message });
  }
});

// Update user
router.put('/:id', auth, (req, res) => {
  try {
    const { first_name, last_name, phone, address, gender, date_of_birth, emergency_contact, emergency_phone, profile_image, role, department_id } = req.body;
    
    const isPrivileged = ['admin', 'principal'].includes(req.user.role);

    // Only allow self or admin to update
    if (!isPrivileged && req.user.id !== parseInt(req.params.id)) {
      return res.status(403).json({ error: 'You can only update your own profile' });
    }
    
    // Only privileged users can update role or department
    const finalRole = isPrivileged && role ? role : undefined;
    const finalDept = isPrivileged && department_id ? department_id : undefined;

    getDb().prepare(`
      UPDATE users SET
        first_name = COALESCE(?, first_name),
        last_name = COALESCE(?, last_name),
        phone = COALESCE(?, phone),
        address = COALESCE(?, address),
        gender = COALESCE(?, gender),
        date_of_birth = COALESCE(?, date_of_birth),
        emergency_contact = COALESCE(?, emergency_contact),
        emergency_phone = COALESCE(?, emergency_phone),
        profile_image = COALESCE(?, profile_image),
        role = COALESCE(?, role),
        department_id = COALESCE(?, department_id),
        updated_at = CURRENT_TIMESTAMP,
        sync_status = 'pending'
      WHERE id = ? AND is_deleted = 0
    `).run(first_name, last_name, phone, address, gender, date_of_birth, emergency_contact, emergency_phone, profile_image, finalRole, finalDept, req.params.id);
    
    const updated = getDb().prepare('SELECT id, uid, email, role, first_name, last_name, phone, address, is_active FROM users WHERE id = ?').get(req.params.id);
    
    if (!updated) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    res.json(updated);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Change password
router.put('/:id/password', auth, (req, res) => {
  try {
    const { current_password, new_password } = req.body;
    
    // Only self or admin can change password
    if (req.user.role !== 'admin' && req.user.id !== parseInt(req.params.id)) {
      return res.status(403).json({ error: 'You can only change your own password' });
    }
    
    const user = getDb().prepare('SELECT password FROM users WHERE id = ? AND is_deleted = 0').get(req.params.id);
    
    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }
    
    // Verify current password (admin bypasses this)
    if (req.user.role !== 'admin') {
      if (!current_password || !bcrypt.compareSync(current_password, user.password)) {
        return res.status(400).json({ error: 'Current password is incorrect' });
      }
    }
    
    if (!new_password || new_password.length < 6) {
      return res.status(400).json({ error: 'New password must be at least 6 characters' });
    }
    
    const hashedPassword = bcrypt.hashSync(new_password, 10);
    
    getDb().prepare(`
      UPDATE users SET password = ?, updated_at = CURRENT_TIMESTAMP, sync_status = 'pending'
      WHERE id = ?
    `).run(hashedPassword, req.params.id);
    
    res.json({ success: true, message: 'Password updated successfully' });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Deactivate/activate user
router.patch('/:id/status', auth, adminOnly, (req, res) => {
  try {
    const { is_active } = req.body;
    
    getDb().prepare(`
      UPDATE users SET is_active = ?, updated_at = CURRENT_TIMESTAMP, sync_status = 'pending'
      WHERE id = ? AND is_deleted = 0
    `).run(is_active ? 1 : 0, req.params.id);
    
    res.json({ success: true });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// Delete user (soft delete)
router.delete('/:id', auth, adminOnly, (req, res) => {
  try {
    getDb().prepare(`
      UPDATE users SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP, sync_status = 'pending'
      WHERE id = ?
    `).run(req.params.id);
    
    res.json({ success: true, message: 'User deleted successfully' });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// ============ BULK OPERATIONS ============

// Bulk import users
router.post('/bulk', auth, adminOnly, (req, res) => {
  try {
    const { users } = req.body;
    
    if (!Array.isArray(users) || users.length === 0) {
      return res.status(400).json({ error: 'Users array required' });
    }
    
    const insert = getDb().prepare(`
      INSERT INTO users (uid, email, password, role, first_name, last_name, phone, address, gender, date_of_birth)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `);
    
    const insertMany = getDb().transaction((users) => {
      const results = [];
      for (const user of users) {
        try {
          const hashedPassword = bcrypt.hashSync(user.password || 'changeme123', 10);
          const uid = uuidv4();
          insert.run(uid, user.email, hashedPassword, user.role || 'student', user.first_name, user.last_name, user.phone, user.address, user.gender, user.date_of_birth);
          results.push({ email: user.email, id: insert.lastInsertRowid, success: true });
        } catch (e) {
          results.push({ email: user.email, error: e.message, success: false });
        }
      }
      return results;
    });
    
    const results = insertMany(users);
    
    res.status(201).json({
      created: results.filter(r => r.success).length,
      failed: results.filter(r => !r.success).length,
      results
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// ============ STATS ============

// Get user statistics
router.get('/stats/overview', auth, (req, res) => {
  try {
    const stats = getDb().prepare(`
      SELECT 
        role,
        COUNT(*) as total,
        SUM(CASE WHEN is_active = 1 THEN 1 ELSE 0 END) as active,
        SUM(CASE WHEN is_active = 0 THEN 1 ELSE 0 END) as inactive
      FROM users
      WHERE is_deleted = 0
      GROUP BY role
    `).all();
    
    const total = getDb().prepare('SELECT COUNT(*) as count FROM users WHERE is_deleted = 0').get().count;
    
    res.json({
      total,
      by_role: stats.reduce((acc, s) => {
        acc[s.role] = { total: s.total, active: s.active, inactive: s.inactive };
        return acc;
      }, {})
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

module.exports = router;