// controllers/userController.js
'use strict';
const bcrypt = require('bcrypt');
const { User, Store, Session, Transaction, AuditLog, StockMovement, CashDrawerActivity,sequelize } = require('../models');
const { Op } = require('sequelize');

class UserController {
  // Get all users with filtering and pagination
  async getAllUsers(req, res) {
    try {
      const {
        page = 1,
        limit = 10,
        search = '',
        role = '',
        isActive = '',
        storeId = '',
        sortBy = 'createdAt',
        sortOrder = 'DESC'
      } = req.query;

      const offset = (page - 1) * limit;
      const where = {};

      // Apply filters
      if (search) {
        where[Op.or] = [
          { firstName: { [Op.like]: `%${search}%` } },
          { lastName: { [Op.like]: `%${search}%` } },
          { username: { [Op.like]: `%${search}%` } },
          { email: { [Op.like]: `%${search}%` } }
        ];
      }

      if (role) where.role = role;
      if (isActive !== '') where.isActive = isActive === 'true';
      if (storeId) where.storeId = storeId;

      const { count, rows: users } = await User.findAndCountAll({
        where,
        include: [
          {
            model: Store,
            as: 'store',
            attributes: ['id', 'name', 'address']
          }
        ],
        attributes: { exclude: ['password'] },
        limit: parseInt(limit),
        offset: parseInt(offset),
        order: [[sortBy, sortOrder]]
      });

      // Get activity stats for each user
      const usersWithStats = await Promise.all(
        users.map(async (user) => {
          const [transactionCount, sessionCount, auditLogCount] = await Promise.all([
            Transaction.count({ where: { cashierId: user.id } }),
            Session.count({ where: { userId: user.id } }),
            AuditLog.count({ where: { userId: user.id } })
          ]);

          return {
            ...user.toJSON(),
            stats: {
              transactions: transactionCount,
              sessions: sessionCount,
              auditLogs: auditLogCount
            }
          };
        })
      );

      res.json({
        success: true,
        data: {
          users: usersWithStats,
          pagination: {
            total: count,
            page: parseInt(page),
            limit: parseInt(limit),
            totalPages: Math.ceil(count / limit)
          }
        }
      });
    } catch (error) {
      console.error('Get users error:', error);
      res.status(500).json({
        success: false,
        message: 'Error fetching users',
        error: error.message
      });
    }
  }

  // Get user by ID with all relationships
  async getUserById(req, res) {
    try {
      const { id } = req.params;
      const { includeRelations = 'basic' } = req.query;

      const includeOptions = [
        {
          model: Store,
          as: 'store',
          attributes: ['id', 'name', 'address', 'phone']
        }
      ];

      // Add detailed relations if requested
      if (includeRelations === 'full') {
        includeOptions.push(
          {
            model: Session,
            as: 'sessions',
            limit: 10,
            order: [['createdAt', 'DESC']],
            attributes: ['id', 'loginTime', 'logoutTime', 'ipAddress']
          },
          {
            model: Transaction,
            as: 'transactions',
            limit: 10,
            order: [['createdAt', 'DESC']],
            attributes: ['id', 'totalAmount', 'paymentMethod', 'createdAt']
          },
          {
            model: AuditLog,
            as: 'auditLogs',
            limit: 10,
            order: [['createdAt', 'DESC']],
            attributes: ['id', 'action', 'tableName', 'createdAt']
          }
        );
      }

      const user = await User.findByPk(id, {
        include: includeOptions,
        attributes: { exclude: ['password'] }
      });

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

      // Get aggregated stats
      const [
        totalTransactions,
        totalSales,
        stockMovements,
        cashActivities,
        activeSessions
      ] = await Promise.all([
        Transaction.count({ where: { cashierId: id } }),
        Transaction.sum('totalAmount', { where: { cashierId: id } }),
        StockMovement.count({ where: { performedBy: id } }),
        CashDrawerActivity.count({ where: { performedBy: id } }),
        Session.count({ where: { userId: id, logoutTime: null } })
      ]);

      const userData = user.toJSON();
      userData.stats = {
        totalTransactions,
        totalSales: totalSales || 0,
        stockMovements,
        cashActivities,
        activeSessions
      };

      res.json({
        success: true,
        data: userData
      });
    } catch (error) {
      console.error('Get user by ID error:', error);
      res.status(500).json({
        success: false,
        message: 'Error fetching user',
        error: error.message
      });
    }
  }

  // Create new user
  // async createUser(req, res) {
  //   try {
  //     const {
  //       firstName,
  //       lastName,
  //       username,
  //       email,
  //       password,
  //       phone,
  //       role,
  //       pin,
  //       storeId,
  //       isActive = true
  //     } = req.body;

  //     console.log('CREATED USER WITH THIS:', req.body);

  //     // Validate required fields
  //     if (!firstName || !lastName || !username || !email || !password || !role || !pin) {
  //       return res.status(400).json({
  //         success: false,
  //         message: 'Missing required fields'
  //       });
  //     }

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

  //     // Check if username or email already exists
  //     const existingUser = await User.findOne({
  //       where: {
  //         [Op.or]: [{ username }, { email }]
  //       }
  //     });

  //     if (existingUser) {
  //       return res.status(409).json({
  //         success: false,
  //         message: existingUser.username === username 
  //           ? 'Username already exists' 
  //           : 'Email already exists'
  //       });
  //     }

  //     // Hash password and PIN
  //     const hashedPassword = await bcrypt.hash(password, 10);
  //     const hashedPin = await bcrypt.hash(pin, 10);

  //     // Create user
  //     const user = await User.create({
  //       firstName,
  //       lastName,
  //       username,
  //       email,
  //       password: hashedPassword,
  //       phone,
  //       role,
  //       pin: hashedPin,
  //       storeId,
  //       isActive
  //     });

  //     // Log audit
  //     await AuditLog.create({
  //       userId: req.user?.id || null,
  //       action: 'CREATE',
  //       tableName: 'users',
  //       recordId: user.id,
  //       changes: JSON.stringify({ created: true, role, username })
  //     });

  //     // Return user without password
  //     const userResponse = user.toJSON();
  //     delete userResponse.password;
  //     delete userResponse.pin;

  //     res.status(201).json({
  //       success: true,
  //       message: 'User created successfully',
  //       data: userResponse
  //     });
  //   } catch (error) {
  //     console.error('Create user error:', error);
  //     res.status(500).json({
  //       success: false,
  //       message: 'Error creating user',
  //       error: error.message
  //     });
  //   }
  // }


  async createUser(req, res) {
  try {
    const {
      firstName,
      lastName,
      username,
      email,
      password,
      phone,
      role,
      pin,
      storeId,
      isActive = true
    } = req.body;

    // Validate required fields
    if (!firstName || !lastName || !username || !email || !password || !role || !pin) {
      return res.status(400).json({
        success: false,
        message: 'Missing required fields'
      });
    }

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

    // Check username/email uniqueness
    const existingUser = await User.findOne({
      where: {
        [Op.or]: [{ username }, { email }]
      }
    });

    if (existingUser) {
      return res.status(409).json({
        success: false,
        message: existingUser.username === username
          ? 'Username already exists'
          : 'Email already exists'
      });
    }

    // CHECK FOR DUPLICATE PIN (hashed comparison)
    const usersWithPin = await User.findAll({
      where: { pin: { [Op.ne]: null } },
      attributes: ['id', 'pin']
    });

    for (const u of usersWithPin) {
      const isMatch = await bcrypt.compare(pin, u.pin);
      if (isMatch) {
        return res.status(409).json({
          success: false,
          message: 'This PIN is already assigned to another user'
        });
      }
    }

    // Hash password and PIN
    const hashedPassword = await bcrypt.hash(password, 12);
    const hashedPin = await bcrypt.hash(pin, 12);

     // Extract first + last digit as hint
      const pinString = pin.toString();
      const pinHint = pinString[0] + pinString[3]; // e.g., '1234' -> '14'

    // Create user
    const user = await User.create({
      firstName,
      lastName,
      username,
      email,
      password: hashedPassword,
      phone,
      role,
      pin: hashedPin,
      pinHint,
      storeId,
      isActive
    });

    // Audit log
    await AuditLog.create({
      userId: req.user?.id || null,
      action: 'CREATE',
      tableName: 'users',
      recordId: user.id,
      changes: JSON.stringify({ created: true, role, username })
    });

    const userResponse = user.toJSON();
    delete userResponse.password;
    delete userResponse.pin;

    res.status(201).json({
      success: true,
      message: 'User created successfully',
      data: userResponse
    });
  } catch (error) {
    console.error('Create user error:', error);
    res.status(500).json({
      success: false,
      message: 'Error creating user',
      error: error.message
    });
  }
}

  // Update user
async updateUser(req, res) {
  try {
    const { id } = req.params;
    const {
      firstName,
      lastName,
      username,
      email,
      phone,
      role,
      pin,           // ← New: allow updating PIN
      storeId,
      isActive
    } = req.body;

    const user = await User.findByPk(id);
    if (!user) {
      return res.status(404).json({
        success: false,
        message: 'User not found'
      });
    }

    // Username uniqueness (if changing)
    if (username && username !== user.username) {
      const exists = await User.findOne({ where: { username } });
      if (exists) {
        return res.status(409).json({
          success: false,
          message: 'Username already exists'
        });
      }
    }

    // Email uniqueness (if changing)
    if (email && email !== user.email) {
      const exists = await User.findOne({ where: { email } });
      if (exists) {
        return res.status(409).json({
          success: false,
          message: 'Email already exists'
        });
      }
    }

    // PIN: if provided, validate format and check uniqueness (except current user)
    let newHashedPin = user.pin;
    if (pin !== undefined) {
      if (pin === null || pin === '') {
        newHashedPin = null; // Allow clearing PIN
      } else {
        if (!/^\d{4}$/.test(pin)) {
          return res.status(400).json({
            success: false,
            message: 'PIN must be exactly 4 digits'
          });
        }

        // Check if PIN is already used by another user
        const otherUsers = await User.findAll({
          where: {
            id: { [Op.ne]: user.id },
            pin: { [Op.ne]: null }
          },
          attributes: ['id', 'pin']
        });

        for (const u of otherUsers) {
          const match = await bcrypt.compare(pin, u.pin);
          if (match) {
            return res.status(409).json({
              success: false,
              message: 'This PIN is already assigned to another user'
            });
          }
        }

        newHashedPin = await bcrypt.hash(pin, 12);
      }
    }

    const oldValues = { ...user.toJSON() };

    const pinString = pin.toString();
    const pinHint = pinString[0] + pinString[3]; // e.g., '1234' -> '14'

    // Update user
    await user.update({
      firstName: firstName || user.firstName,
      lastName: lastName || user.lastName,
      username: username || user.username,
      email: email || user.email,
      phone: phone !== undefined ? phone : user.phone,
      role: role || user.role,
      storeId: storeId || user.storeId,
      isActive: isActive !== undefined ? isActive : user.isActive,
      pin: newHashedPin,
      pinHint: pin ? pinHint : user.pinHint
    });

    // Audit log
    await AuditLog.create({
      userId: req.user?.id || null,
      action: 'UPDATE',
      tableName: 'users',
      recordId: user.id,
      changes: JSON.stringify({
        old: oldValues,
        new: user.toJSON()
      })
    });

    const userResponse = user.toJSON();
    delete userResponse.password;
    delete userResponse.pin;

    res.json({
      success: true,
      message: 'User updated successfully',
      data: userResponse
    });
  } catch (error) {
    console.error('Update user error:', error);
    res.status(500).json({
      success: false,
      message: 'Error updating user',
      error: error.message
    });
  }
}
  // Update password
  async updatePassword(req, res) {
    try {
      const { id } = req.params;
      const { currentPassword, newPassword, newPin } = req.body;

      // Check if user is updating their own password or is admin
      if (req.user?.id !== parseInt(id) && req.user?.role !== 'Admin') {
        return res.status(403).json({
          success: false,
          message: 'Not authorized to update this password'
        });
      }

      const user = await User.findByPk(id);

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

      // Verify current password if not admin
      if (req.user?.role !== 'Admin') {
        const isValidPassword = await bcrypt.compare(currentPassword, user.password);
        if (!isValidPassword) {
          return res.status(401).json({
            success: false,
            message: 'Current password is incorrect'
          });
        }
      }

      // Validate new password
      if (!newPassword || newPassword.length < 6) {
        return res.status(400).json({
          success: false,
          message: 'New password must be at least 6 characters'
        });
      }

      // Hash new password
      const hashedPassword = await bcrypt.hash(newPassword, 10);
      const updateData = { password: hashedPassword };

      // Update PIN if provided
      if (newPin) {
        if (!/^\d{4}$/.test(newPin)) {
          return res.status(400).json({
            success: false,
            message: 'PIN must be exactly 4 digits'
          });
        }
        updateData.pin = await bcrypt.hash(newPin, 10);
      }

      await user.update(updateData);

      // Log audit
      await AuditLog.create({
        userId: req.user?.id || null,
        action: 'UPDATE_PASSWORD',
        tableName: 'users',
        recordId: user.id,
        changes: JSON.stringify({ passwordChanged: true, pinChanged: !!newPin })
      });

      res.json({
        success: true,
        message: 'Password updated successfully'
      });
    } catch (error) {
      console.error('Update password error:', error);
      res.status(500).json({
        success: false,
        message: 'Error updating password',
        error: error.message
      });
    }
  }

  // Toggle user active status
  async toggleUserStatus(req, res) {
    try {
      const { id } = req.params;

      const user = await User.findByPk(id);

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

      // Prevent deactivating self
      if (req.user?.id === parseInt(id)) {
        return res.status(400).json({
          success: false,
          message: 'Cannot deactivate your own account'
        });
      }

      const newStatus = !user.isActive;
      await user.update({ isActive: newStatus });

      // Log audit
      await AuditLog.create({
        userId: req.user?.id || null,
        action: newStatus ? 'ACTIVATE' : 'DEACTIVATE',
        tableName: 'users',
        recordId: user.id,
        changes: JSON.stringify({ isActive: newStatus })
      });

      res.json({
        success: true,
        message: `User ${newStatus ? 'activated' : 'deactivated'} successfully`,
        data: { isActive: newStatus }
      });
    } catch (error) {
      console.error('Toggle user status error:', error);
      res.status(500).json({
        success: false,
        message: 'Error toggling user status',
        error: error.message
      });
    }
  }

  // Delete user (soft delete - deactivate)
  async deleteUser(req, res) {
    try {
      const { id } = req.params;
      const { hardDelete = false } = req.query;

      const user = await User.findByPk(id);

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

      // Prevent deleting self
      if (req.user?.id === parseInt(id)) {
        return res.status(400).json({
          success: false,
          message: 'Cannot delete your own account'
        });
      }

      // Check if user has related records
      const [transactions, sessions, auditLogs] = await Promise.all([
        Transaction.count({ where: { cashierId: id } }),
        Session.count({ where: { userId: id } }),
        AuditLog.count({ where: { userId: id } })
      ]);

      if (transactions > 0 || sessions > 0 || auditLogs > 0) {
        if (hardDelete) {
          return res.status(400).json({
            success: false,
            message: 'Cannot hard delete user with related records. Use soft delete instead.',
            relatedRecords: { transactions, sessions, auditLogs }
          });
        }
      }

      if (hardDelete && req.user?.role === 'Admin') {
        await user.destroy();
        await AuditLog.create({
          userId: req.user?.id || null,
          action: 'HARD_DELETE',
          tableName: 'users',
          recordId: id,
          changes: JSON.stringify({ deleted: true })
        });
        return res.json({
          success: true,
          message: 'User permanently deleted'
        });
      }

      // Soft delete - just deactivate
      await user.update({ isActive: false });

      await AuditLog.create({
        userId: req.user?.id || null,
        action: 'SOFT_DELETE',
        tableName: 'users',
        recordId: id,
        changes: JSON.stringify({ deactivated: true })
      });

      res.json({
        success: true,
        message: 'User deactivated successfully'
      });
    } catch (error) {
      console.error('Delete user error:', error);
      res.status(500).json({
        success: false,
        message: 'Error deleting user',
        error: error.message
      });
    }
  }

  // Get user activity summary
  async getUserActivity(req, res) {
    try {
      const { id } = req.params;
      const { startDate, endDate } = req.query;

      const user = await User.findByPk(id);

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

      const dateFilter = {};
      if (startDate) dateFilter.createdAt = { [Op.gte]: new Date(startDate) };
      if (endDate) {
        dateFilter.createdAt = {
          ...dateFilter.createdAt,
          [Op.lte]: new Date(endDate)
        };
      }

      // Get detailed activity
      const [
        transactions,
        sessions,
        stockMovements,
        cashActivities,
        recentAuditLogs
      ] = await Promise.all([
        Transaction.findAll({
          where: { cashierId: id, ...dateFilter },
          order: [['createdAt', 'DESC']],
          limit: 20,
          attributes: ['id', 'totalAmount', 'paymentMethod', 'createdAt']
        }),
        Session.findAll({
          where: { userId: id, ...dateFilter },
          order: [['loginTime', 'DESC']],
          limit: 10
        }),
        StockMovement.findAll({
          where: { performedBy: id, ...dateFilter },
          order: [['createdAt', 'DESC']],
          limit: 20,
          attributes: ['id', 'productId', 'quantity', 'type', 'createdAt']
        }),
        CashDrawerActivity.findAll({
          where: { performedBy: id, ...dateFilter },
          order: [['createdAt', 'DESC']],
          limit: 20,
          attributes: ['id', 'type', 'amount', 'createdAt']
        }),
        AuditLog.findAll({
          where: { userId: id, ...dateFilter },
          order: [['createdAt', 'DESC']],
          limit: 50,
          attributes: ['id', 'action', 'tableName', 'createdAt']
        })
      ]);

      res.json({
        success: true,
        data: {
          user: {
            id: user.id,
            firstName: user.firstName,
            lastName: user.lastName,
            role: user.role
          },
          activity: {
            transactions,
            sessions,
            stockMovements,
            cashActivities,
            auditLogs: recentAuditLogs
          },
          summary: {
            totalTransactions: transactions.length,
            totalSales: transactions.reduce((sum, t) => sum + parseFloat(t.totalAmount || 0), 0),
            totalSessions: sessions.length,
            totalStockMovements: stockMovements.length,
            totalCashActivities: cashActivities.length
          }
        }
      });
    } catch (error) {
      console.error('Get user activity error:', error);
      res.status(500).json({
        success: false,
        message: 'Error fetching user activity',
        error: error.message
      });
    }
  }

  // Get user statistics
  async getUserStats(req, res) {
    try {
      const totalUsers = await User.count();
      const activeUsers = await User.count({ where: { isActive: true } });
      const inactiveUsers = await User.count({ where: { isActive: false } });

      // Count by role
      const roleStats = await User.findAll({
        attributes: [
          'role',
          [sequelize.fn('COUNT', sequelize.col('id')), 'count']
        ],
        group: ['role']
      });

      // Recent logins
      const recentLogins = await User.findAll({
        where: {
          lastLogin: { [Op.not]: null }
        },
        order: [['lastLogin', 'DESC']],
        limit: 10,
        attributes: ['id', 'firstName', 'lastName', 'lastLogin', 'role']
      });

      res.json({
        success: true,
        data: {
          total: totalUsers,
          active: activeUsers,
          inactive: inactiveUsers,
          byRole: roleStats,
          recentLogins
        }
      });
    } catch (error) {
      console.error('Get user stats error:', error);
      res.status(500).json({
        success: false,
        message: 'Error fetching user statistics',
        error: error.message
      });
    }
  }

  // Verify PIN
  async verifyPin(req, res) {
    try {
      const { username, pin } = req.body;

      if (!username || !pin) {
        return res.status(400).json({
          success: false,
          message: 'Username and PIN are required'
        });
      }

      const user = await User.findOne({
        where: { username, isActive: true }
      });

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

      const isValidPin = await bcrypt.compare(pin, user.pin);

      if (!isValidPin) {
        return res.status(401).json({
          success: false,
          message: 'Invalid PIN'
        });
      }

      res.json({
        success: true,
        message: 'PIN verified successfully',
        data: {
          id: user.id,
          firstName: user.firstName,
          lastName: user.lastName,
          role: user.role
        }
      });
    } catch (error) {
      console.error('Verify PIN error:', error);
      res.status(500).json({
        success: false,
        message: 'Error verifying PIN',
        error: error.message
      });
    }
  }
}

module.exports = new UserController();


