// controllers/authController.js
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { User, Session, Store, RegisterAssignment,Customer, Register } = require('../models');

const { Op } = require('sequelize');



// Register new user
// exports.register = async (req, res) => {
//   try {
//     const { username, email, password, firstName, lastName, phone, role = 'customer' } = req.body;

//     // Validate required fields
//     if (!email || !password || !firstName) {
//       return res.status(400).json({ 
//         success: false,
//         message: 'Email, password, and name are required | Barua pepe, nywila, na jina vinahitajika' 
//       });
//     }

//     // Check if user exists
//     const existingUser = await User.findOne({ 
//       where: { 
//         [Op.or]: [{ email }, { username: username || email.split('@')[0] }]
//       } 
//     });

//     if (existingUser) {
//       return res.status(400).json({ 
//         success: false,
//         message: 'User already exists | Mtumiaji tayari yupo' 
//       });
//     }

//     // Hash password
//     const hashedPassword = await bcrypt.hash(password, 10);

//     // Create user
//     const user = await User.create({
//       username: username || email.split('@')[0],
//       email,
//       password: hashedPassword,
//       firstName,
//       lastName: lastName || firstName,
//       phone,
//       role: role === 'admin' ? 'customer' : role, // Prevent self-promotion to admin
//       isActive: true
//     });

//     // Generate token
//     const token = jwt.sign(
//       { 
//         id: user.id, 
//         email: user.email, 
//         role: user.role 
//       },
//       process.env.JWT_SECRET,
//       { expiresIn: '7d' }
//     );

//     // Create session
//     await Session.create({
//       userId: user.id,
//       token,
//       ipAddress: req.ip,
//       userAgent: req.headers['user-agent'],
//       expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7 days
//     });

//     res.status(201).json({
//       success: true,
//       message: 'Account created successfully | Akaunti imetengenezwa',
//       token,
//       user: {
//         id: user.id,
//         username: user.username,
//         email: user.email,
//         firstName: user.firstName,
//         lastName: user.lastName,
//         phone: user.phone,
//         role: user.role,
//         isActive: user.isActive
//       }
//     });
//   } catch (error) {
//     console.error('Registration error:', error);
//     res.status(500).json({ 
//       success: false,
//       message: 'Error creating account | Kosa limetokea' 
//     });
//   }
// };


// Register new user
exports.register = async (req, res) => {
  try {
    const { username, email, password, firstName, lastName, phone, role = 'customer' } = req.body;

    // Validate required fields
    if (!email || !password || !firstName) {
      return res.status(400).json({ 
        success: false,
        message: 'Email, password, and name are required | Barua pepe, nywila, na jina vinahitajika' 
      });
    }

    // Check if user exists
    const existingUser = await User.findOne({ 
      where: { 
        [Op.or]: [{ email }, { username: username || email.split('@')[0] }]
      } 
    });

    if (existingUser) {
      return res.status(400).json({ 
        success: false,
        message: 'User already exists | Mtumiaji tayari yupo' 
      });
    }

    // Hash password
    const hashedPassword = await bcrypt.hash(password, 10);

    // Create user
    const user = await User.create({
      username: username || email.split('@')[0],
      email,
      password: hashedPassword,
      firstName,
      lastName: lastName || firstName,
      phone,
      role: role === 'admin' ? 'customer' : role, // Prevent self-promotion to admin
      isActive: true
    });

    // ✅ CREATE CUSTOMER RECORD ONLY FOR CUSTOMER ROLE
    if (user.role === 'customer') {
      try {
        await Customer.create({
          userId: user.id,
          firstName: user.firstName,
          lastName: user.lastName || user.firstName,
          email: user.email,
          phone: user.phone,
          tier: 'bronze',
          status: 'active',
          loyaltyPoints: 0,
          registrationDate: new Date()
        });
        console.log(`✅ Customer record created for user ${user.id}`);
      } catch (customerError) {
        console.error('❌ Error creating customer record:', customerError);
        // Don't fail the entire registration if customer creation fails
        // The user account is still created successfully
      }
    }

    // Generate token
    const token = jwt.sign(
      { 
        id: user.id, 
        email: user.email, 
        role: user.role 
      },
      process.env.JWT_SECRET,
      { expiresIn: '7d' }
    );

    // Create session
    await Session.create({
      userId: user.id,
      token,
      ipAddress: req.ip,
      userAgent: req.headers['user-agent'],
      expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7 days
    });

    res.status(201).json({
      success: true,
      message: 'Account created successfully | Akaunti imetengenezwa',
      token,
      user: {
        id: user.id,
        username: user.username,
        email: user.email,
        firstName: user.firstName,
        lastName: user.lastName,
        phone: user.phone,
        role: user.role,
        isActive: user.isActive
      }
    });
  } catch (error) {
    console.error('Registration error:', error);
    res.status(500).json({ 
      success: false,
      message: 'Error creating account | Kosa limetokea' 
    });
  }
};

// Login user
exports.login = async (req, res) => {
  try {
    const { email, password } = req.body;

    if (!email || !password) {
      return res.status(400).json({ 
        success: false,
        message: 'Email and password are required | Barua pepe na nywila zinahitajika' 
      });
    }

    // Find user by email
    const user = await User.findOne({
      where: { 
        email,
        isActive: true 
      }
    });

    if (!user) {
      return res.status(401).json({ 
        success: false,
        message: 'Invalid credentials | Taarifa za kuingia si sahihi' 
      });
    }

    // Check password
    const isValidPassword = await bcrypt.compare(password, user.password);
    if (!isValidPassword) {
      return res.status(401).json({ 
        success: false,
        message: 'Invalid credentials | Taarifa za kuingia si sahihi' 
      });
    }

    // Generate token
    const token = jwt.sign(
      { 
        id: user.id, 
        email: user.email, 
        role: user.role 
      },
      process.env.JWT_SECRET,
      { expiresIn: '7d' }
    );

    // Destroy any existing sessions for this user
    await Session.destroy({
      where: { userId: user.id }
    });

    // Create new session
    await Session.create({
      userId: user.id,
      token,
      ipAddress: req.ip,
      userAgent: req.headers['user-agent'],
      expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
    });

    // Update last login timestamp
    await user.update({ lastLogin: new Date() });

    res.json({
      success: true,
      message: 'Login successful | Umeingia',
      token,
      user: {
        id: user.id,
        username: user.username,
        email: user.email,
        firstName: user.firstName,
        lastName: user.lastName,
        phone: user.phone,
        role: user.role,
        isActive: user.isActive
      }
    });
  } catch (error) {
    console.error('Login error:', error);
    res.status(500).json({ 
      success: false,
      message: 'Login failed | Kuingia kumeshindikana' 
    });
  }
};

// Logout user
exports.logout = async (req, res) => {
  try {
    const token = req.headers.authorization?.split(' ')[1];
    
    if (token) {
      await Session.destroy({ where: { token } });
    }
    
    res.json({ 
      success: true,
      message: 'Logged out successfully | Umetoka' 
    });
  } catch (error) {
    console.error('Logout error:', error);
    res.status(500).json({ 
      success: false,
      message: 'Error logging out | Kosa limetokea' 
    });
  }
};

// Get user profile
exports.getProfile = async (req, res) => {
  try {
    const user = await User.findByPk(req.user.id, {
      attributes: { exclude: ['password'] }
    });

    if (!user) {
      return res.status(404).json({ 
        success: false,
        message: 'User not found | Mtumiaji hajapatikana' 
      });
    }

    res.json({
      success: true,
      user: {
        id: user.id,
        username: user.username,
        email: user.email,
        firstName: user.firstName,
        lastName: user.lastName,
        phone: user.phone,
        role: user.role,
        isActive: user.isActive
      }
    });
  } catch (error) {
    console.error('Get profile error:', error);
    res.status(500).json({ 
      success: false,
      message: 'Error fetching profile | Kosa limetokea' 
    });
  }
};

// Verify token
exports.verifyToken = async (req, res) => {
  try {
    res.json({
      success: true,
      valid: true,
      user: {
        id: req.user.id,
        email: req.user.email,
        role: req.user.role
      }
    });
  } catch (error) {
    console.error('Token verification error:', error);
    res.status(500).json({ 
      success: false,
      error: 'Verification failed' 
    });
  }
};



exports.loginEmail = async (req, res) => {
  try {
    const { username, password } = req.body;

    console.log('Login attempt for email:', username);

    // Find user
    const user = await User.findOne({ 
      where: { email: username, isActive: true },
      include: [{ model: Store, as: 'store' }]
    });

    if (!user) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }

    // Check password
    const isValidPassword = await bcrypt.compare(password, user.password);
    if (!isValidPassword) {
      return res.status(401).json({ message: 'Invalid credentials' });
    }

    // Generate token
    const token = jwt.sign(
      { id: user.id, email: user.email, role: user.role },
      process.env.JWT_SECRET,
      { expiresIn: '8h' }
    );

    // Create session
    await Session.create({
      userId: user.id,
      token,
      ipAddress: req.ip,
      userAgent: req.headers['user-agent'],
      expiresAt: new Date(Date.now() + 8 * 60 * 60 * 1000)
    });

    // Update last login
    await user.update({ lastLogin: new Date() });

    res.json({
      message: 'Login successful',
      token,
      user: {
        id: user.id,
        username: user.username,
        email: user.email,
        firstName: user.firstName,
        lastName: user.lastName,
        role: user.role,
        store: user.store
      }
    });
  } catch (error) {
    res.status(500).json({ message: 'Error logging in', error: error.message });
  }
};

// === NEW: PIN-based login for POS users ===
// exports.loginWithPin = async (req, res) => {
//   try {
//     const { pin, storeId } = req.body;

//     if (!pin || pin.toString().length !== 4 || !/^\d{4}$/.test(pin)) {
//       return res.status(400).json({ message: 'PIN must be exactly 4 digits' });
//     }

//     // Step 1: Get ALL active users who have a PIN set
//     const usersWithPin = await User.findAll({
//       where: {
//         isActive: true,
//         pin: { [Op.ne]: null } // Has a PIN
//       },
//       include: [
//         { model: Store, as: 'store' },
//         { model: Register, as: 'openedRegisters' },
//         { model: RegisterAssignment, as: 'registerAssignments' },
//         {
//           model: Register,
//           as: 'assignedRegisters',
//           through: { attributes: ['id', 'assignedAt', 'isPrimary', 'isActive'] },
//         },
//       ],
//     });

//     // Step 2: Loop through users and compare entered PIN with their hashed PIN
//     let authenticatedUser = null;

//     for (const user of usersWithPin) {
//       const isMatch = await bcrypt.compare(pin.toString(), user.pin);
//       if (isMatch) {
//         authenticatedUser = user;
//         break;
//       }
//     }

//     // Step 3: If no match found → invalid PIN
//     if (!authenticatedUser) {
//       return res.status(401).json({ message: 'Invalid PIN' });
//     }

//     console.log('PIN login successful for:', authenticatedUser.username, 'Role:', authenticatedUser.role);

//     // Optional: Validate store access
//     if (storeId && authenticatedUser.storeId !== parseInt(storeId, 10)) {
//       return res.status(403).json({ message: 'User does not belong to this store' });
//     }

//     // Generate JWT
//     const token = jwt.sign(
//       {
//         id: authenticatedUser.id,
//         username: authenticatedUser.username,
//         role: authenticatedUser.role,
//         store_id: authenticatedUser.storeId,
//       },
//       process.env.JWT_SECRET,
//       { expiresIn: '8h' }
//     );

//     // Invalidate old sessions
//     await Session.destroy({ where: { userId: authenticatedUser.id } });

//     // Create new session
//     await Session.create({
//       userId: authenticatedUser.id,
//       token,
//       ipAddress: req.ip,
//       userAgent: req.headers['user-agent'],
//       expiresAt: new Date(Date.now() + 8 * 60 * 60 * 1000),
//     });

//     // Update last login
//     await authenticatedUser.update({ lastLogin: new Date() });

//     // Return user data
//     res.json({
//       message: 'Login successful',
//       token,
//       user: {
//         id: authenticatedUser.id,
//         store_id: authenticatedUser.storeId,
//         username: authenticatedUser.username,
//         firstName: authenticatedUser.firstName,
//         lastName: authenticatedUser.lastName,
//         role: authenticatedUser.role,
//         store: authenticatedUser.store,
//         registerId:
//           authenticatedUser.openedRegisters.length > 0
//             ? authenticatedUser.openedRegisters[0].id
//             : null,
//       },
//     });
//   } catch (error) {
//     console.error('PIN login error:', error);
//     res.status(500).json({ message: 'Login failed. Please try again.' });
//   }
// };

exports.loginWithPin = async (req, res) => {
  try {
    const { pin, storeId } = req.body;

    // Validate PIN format
    if (!pin || pin.toString().length !== 4 || !/^\d{4}$/.test(pin)) {
      return res.status(400).json({ message: 'PIN must be exactly 4 digits' });
    }

    // OPTIMIZATION 1: Fetch only necessary fields to reduce memory footprint
    const usersWithPin = await User.findAll({
      where: {
        isActive: true,
        pin: { [Op.ne]: null }
      },
      attributes: ['id', 'username', 'firstName', 'lastName', 'role', 'storeId', 'pin'],
      include: [
        { 
          model: Store, 
          as: 'store',
          attributes: ['id', 'name'] // Specify only needed store fields
        },
        { 
          model: Register, 
          as: 'openedRegisters',
          attributes: ['id']
        },
      ],
    });

    // OPTIMIZATION 2: Add early exit if no users found
    if (usersWithPin.length === 0) {
      return res.status(401).json({ message: 'Invalid PIN' });
    }

    // OPTIMIZATION 3: Use Promise.all for parallel bcrypt comparisons
    // This is faster than sequential comparisons while maintaining timing safety
    let authenticatedUser = null;
    const comparisonPromises = usersWithPin.map(async (user) => {
      const isMatch = await bcrypt.compare(pin.toString(), user.pin);
      return { user, isMatch };
    });

    const results = await Promise.all(comparisonPromises);
    
    const matchedResult = results.find(r => r.isMatch);
    if (matchedResult) {
      authenticatedUser = matchedResult.user;
    }

    if (!authenticatedUser) {
      return res.status(401).json({ message: 'Invalid PIN' });
    }

    console.log('PIN login successful for:', authenticatedUser.username, 'Role:', authenticatedUser.role);

    // Validate store if provided (PIN determines the store, this just validates)
    if (storeId && authenticatedUser.storeId !== parseInt(storeId, 10)) {
      return res.status(403).json({ message: 'User does not belong to this store' });
    }

    // OPTIMIZATION 4: Fetch full user details with associations only after authentication
    // This avoids loading heavy associations for users who don't match
    const fullUser = await User.findByPk(authenticatedUser.id, {
      include: [
        { 
          model: Store, 
          as: 'store',
          attributes: ['id', 'name', 'address', 'phone'] // Specify needed fields
        },
        { 
          model: Register, 
          as: 'openedRegisters',
          attributes: ['id', 'name']
        },
        {
          model: Register,
          as: 'assignedRegisters',
          attributes: ['id', 'name', 'status'],
          through: { 
            attributes: ['id', 'assignedAt', 'isPrimary', 'isActive'],
            as: 'assignment'
          },
        },
      ],
    });

    // OPTIMIZATION 5: Parallel execution of independent operations
    const token = jwt.sign(
      {
        id: authenticatedUser.id,
        username: authenticatedUser.username,
        role: authenticatedUser.role,
        store_id: authenticatedUser.storeId,
      },
      process.env.JWT_SECRET,
      { expiresIn: '8h' }
    );

    const expiresAt = new Date(Date.now() + 8 * 60 * 60 * 1000);

    // Execute session cleanup, creation, and user update in parallel
    await Promise.all([
      Session.destroy({ where: { userId: fullUser.id } }),
      Session.create({
        userId: fullUser.id,
        token,
        ipAddress: req.ip,
        userAgent: req.headers['user-agent'],
        expiresAt,
      }),
      fullUser.update({ lastLogin: new Date() })
    ]);

    // Return response
    res.json({
      message: 'Login successful',
      token,
      user: {
        id: fullUser.id,
        store_id: fullUser.storeId,
        username: fullUser.username,
        firstName: fullUser.firstName,
        lastName: fullUser.lastName,
        role: fullUser.role,
        store: fullUser.store,
        registerId:
          fullUser.openedRegisters.length > 0
            ? fullUser.openedRegisters[0].id
            : null,
        assignedRegisters: fullUser.assignedRegisters || [],
      },
    });
  } catch (error) {
    console.error('PIN login error:', error);
    res.status(500).json({ message: 'Login failed. Please try again.' });
  }
};

exports.logout = async (req, res) => {
  try {
    const token = req.headers.authorization?.split(' ')[1];
    await Session.destroy({ where: { token } });
    res.json({ message: 'Logged out successfully' });
  } catch (error) {
    res.status(500).json({ message: 'Error logging out', error: error.message });
  }
};



// New function for lock screen UNLOCK verification
exports.verifyPinForUnlock = async (req, res) => {
  try {
    // We expect username (of the locked user) and pin (entered for unlock)
    const { username, pin } = req.body; 

    if (!username || !pin || pin.toString().length !== 4 || !/^\d{4}$/.test(pin)) {
      return res.status(400).json({ message: 'Invalid credentials format.' });
    }

    // Step 1: Find the user by the provided username
    const userToUnlock = await User.findOne({
      where: { 
        username: username,
        isActive: true,
      },
    });

    // Step 2: User not found or no PIN set
    if (!userToUnlock || !userToUnlock.pin) {
      return res.status(401).json({ message: 'Invalid username or PIN.' });
    }

    // Step 3: Compare the entered PIN against the *found user's* hashed PIN
    const isMatch = await bcrypt.compare(pin.toString(), userToUnlock.pin);
    
    // Step 4: Respond based on match
    if (isMatch) {
      // Successfully verified the currently logged-in user's PIN
      return res.json({ success: true, message: 'PIN verified' });
    } else {
      // PIN does not match the user's PIN
      return res.status(401).json({ message: 'Invalid PIN' });
    }

  } catch (error) {
    console.error('PIN verification error:', error);
    res.status(500).json({ message: 'Verification failed.' });
  }
};