const Proposal = require('../models/Proposal');
const Company = require('../models/Company');
const User = require('../models/User');
const Role = require('../models/Role');
const Lead = require('../models/Lead');
const Product = require('../models/Product');
const ActivityLog = require('../models/ActivityLog');

// Get all proposals
exports.getAllProposals = async (req, res, next) => {
  try {
    const { 
      companyId, 
      status, 
      priority,
      workflowStage,
      assignedTo,
      search, 
      page = 1, 
      limit = 10,
      sortBy = 'createdAt',
      sortOrder = 'desc'
    } = req.query;
    
    // Build query
    let query = {};
    
    // Check user role and filter accordingly
    const userRole = await Role.findById(req.user.roleId);
    if (userRole.scope !== 'global') {
      query.companyId = req.user.companyId;
    } else if (companyId) {
      query.companyId = companyId;
    }
    
    // Filter by status
    if (status) {
      query.status = status;
    }
    
    // Filter by priority
    if (priority) {
      query.priority = priority;
    }
    
    // Filter by workflow stage
    if (workflowStage) {
      query['workflow.currentStage'] = workflowStage;
    }
    
    // Filter by assigned user
    if (assignedTo) {
      query.$or = [
        { 'workflow.maker.userId': assignedTo },
        { 'workflow.checker.userId': assignedTo },
        { 'workflow.verifier.userId': assignedTo }
      ];
    }
    
    // Search by proposal number, title, or customer name
    if (search) {
      query.$or = [
        { proposalNumber: { $regex: search, $options: 'i' } },
        { title: { $regex: search, $options: 'i' } },
        { 'customer.name': { $regex: search, $options: 'i' } },
        { 'customer.email': { $regex: search, $options: 'i' } }
      ];
    }
    
    // Pagination
    const skip = (page - 1) * limit;
    
    // Sorting
    const sort = {};
    sort[sortBy] = sortOrder === 'asc' ? 1 : -1;
    
    const proposals = await Proposal.find(query)
      .populate('companyId', 'name code')
      .populate('leadId', 'leadNumber customer')
      .populate('createdBy', 'firstName lastName email')
      .populate('workflow.maker.userId', 'firstName lastName email')
      .populate('workflow.checker.userId', 'firstName lastName email')
      .populate('workflow.verifier.userId', 'firstName lastName email')
      .populate('items.productId', 'name productCode')
      .sort(sort)
      .limit(parseInt(limit))
      .skip(skip);
    
    const total = await Proposal.countDocuments(query);
    
    res.status(200).json({
      success: true,
      count: proposals.length,
      total,
      page: parseInt(page),
      pages: Math.ceil(total / limit),
      data: proposals
    });
  } catch (error) {
    next(error);
  }
};

// Get single proposal
exports.getProposal = async (req, res, next) => {
  try {
    const { id } = req.params;
    
    const proposal = await Proposal.findById(id)
      .populate('companyId', 'name code contact')
      .populate('leadId', 'leadNumber customer')
      .populate('createdBy', 'firstName lastName email')
      .populate('workflow.maker.userId', 'firstName lastName email')
      .populate('workflow.checker.userId', 'firstName lastName email')
      .populate('workflow.verifier.userId', 'firstName lastName email')
      .populate('items.productId', 'name productCode pricing')
      .populate('metadata.revisions.revisedBy', 'firstName lastName');
    
    if (!proposal) {
      return res.status(404).json({
        success: false,
        message: 'Proposal not found'
      });
    }
    
    // Check access
    const userRole = await Role.findById(req.user.roleId);
    if (userRole.scope !== 'global' && proposal.companyId._id.toString() !== req.user.companyId.toString()) {
      return res.status(403).json({
        success: false,
        message: 'You do not have access to this proposal'
      });
    }
    
    // Get workflow history
    const workflowHistory = await ActivityLog.find({
      entityType: 'Proposal',
      entityId: id
    })
      .populate('userId', 'firstName lastName email')
      .sort({ createdAt: -1 })
      .limit(20);
    
    res.status(200).json({
      success: true,
      data: {
        ...proposal.toObject(),
        workflowHistory
      }
    });
  } catch (error) {
    next(error);
  }
};

// Create proposal
exports.createProposal = async (req, res, next) => {
  try {
    const proposalData = req.body;
    
    // Verify company exists
    const company = await Company.findById(proposalData.companyId);
    if (!company) {
      return res.status(404).json({
        success: false,
        message: 'Company not found'
      });
    }
    
    // Check access
    const userRole = await Role.findById(req.user.roleId);
    if (userRole.scope !== 'global' && proposalData.companyId !== req.user.companyId.toString()) {
      return res.status(403).json({
        success: false,
        message: 'You can only create proposals for your own company'
      });
    }
    
    // If leadId provided, verify it exists
    if (proposalData.leadId) {
      const lead = await Lead.findById(proposalData.leadId);
      if (!lead) {
        return res.status(404).json({
          success: false,
          message: 'Lead not found'
        });
      }
    }
    
    // Create proposal
    const proposal = await Proposal.create({
      ...proposalData,
      workflow: {
        ...proposalData.workflow,
        currentStage: 'maker',
        maker: {
          userId: req.user._id,
          status: 'draft',
          comments: ''
        }
      },
      createdBy: req.user._id
    });
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: proposal.companyId,
      action: 'create',
      module: 'proposals',
      entityType: 'Proposal',
      entityId: proposal._id,
      description: `Created proposal: ${proposal.proposalNumber} - ${proposal.title}`,
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    const populatedProposal = await Proposal.findById(proposal._id)
      .populate('companyId', 'name code')
      .populate('leadId', 'leadNumber customer')
      .populate('createdBy', 'firstName lastName email')
      .populate('items.productId', 'name productCode');
    
    res.status(201).json({
      success: true,
      message: 'Proposal created successfully',
      data: populatedProposal
    });
  } catch (error) {
    next(error);
  }
};

// Update proposal
exports.updateProposal = async (req, res, next) => {
  try {
    const { id } = req.params;
    const updates = req.body;
    
    const proposal = await Proposal.findById(id);
    
    if (!proposal) {
      return res.status(404).json({
        success: false,
        message: 'Proposal not found'
      });
    }
    
    // Check access
    const userRole = await Role.findById(req.user.roleId);
    if (userRole.scope !== 'global' && proposal.companyId.toString() !== req.user.companyId.toString()) {
      return res.status(403).json({
        success: false,
        message: 'You do not have access to this proposal'
      });
    }
    
    // Don't allow updating certain fields
    delete updates.proposalNumber;
    delete updates.companyId;
    delete updates.createdBy;
    
    // Track revision
    if (proposal.status !== 'draft') {
      proposal.metadata.version += 1;
      proposal.metadata.revisions.push({
        version: proposal.metadata.version,
        revisedBy: req.user._id,
        revisedAt: new Date(),
        changes: JSON.stringify(updates)
      });
    }
    
    Object.assign(proposal, updates);
    await proposal.save();
    
    const updatedProposal = await Proposal.findById(id)
      .populate('companyId', 'name code')
      .populate('leadId', 'leadNumber customer')
      .populate('createdBy', 'firstName lastName email')
      .populate('workflow.maker.userId', 'firstName lastName email')
      .populate('workflow.checker.userId', 'firstName lastName email')
      .populate('workflow.verifier.userId', 'firstName lastName email')
      .populate('items.productId', 'name productCode');
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: proposal.companyId,
      action: 'update',
      module: 'proposals',
      entityType: 'Proposal',
      entityId: proposal._id,
      description: `Updated proposal: ${proposal.proposalNumber}`,
      changes: updates,
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    res.status(200).json({
      success: true,
      message: 'Proposal updated successfully',
      data: updatedProposal
    });
  } catch (error) {
    next(error);
  }
};

// Delete proposal
exports.deleteProposal = async (req, res, next) => {
  try {
    const { id } = req.params;
    
    const proposal = await Proposal.findById(id);
    
    if (!proposal) {
      return res.status(404).json({
        success: false,
        message: 'Proposal not found'
      });
    }
    
    // Check access
    const userRole = await Role.findById(req.user.roleId);
    if (userRole.scope !== 'global' && proposal.companyId.toString() !== req.user.companyId.toString()) {
      return res.status(403).json({
        success: false,
        message: 'You do not have access to this proposal'
      });
    }
    
    // Don't allow deleting sent/accepted proposals
    if (['sent', 'accepted', 'completed'].includes(proposal.status)) {
      return res.status(400).json({
        success: false,
        message: `Cannot delete proposal with status: ${proposal.status}`
      });
    }
    
    await Proposal.findByIdAndDelete(id);
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: proposal.companyId,
      action: 'delete',
      module: 'proposals',
      entityType: 'Proposal',
      entityId: proposal._id,
      description: `Deleted proposal: ${proposal.proposalNumber}`,
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    res.status(200).json({
      success: true,
      message: 'Proposal deleted successfully'
    });
  } catch (error) {
    next(error);
  }
};

// Submit proposal for review (Maker -> Checker)
exports.submitProposal = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { checkerId, comments } = req.body;
    
    const proposal = await Proposal.findById(id);
    
    if (!proposal) {
      return res.status(404).json({
        success: false,
        message: 'Proposal not found'
      });
    }
    
    // Verify checker exists and has checker role
    const checker = await User.findById(checkerId).populate('roleId');
    if (!checker || checker.roleId.name !== 'checker') {
      return res.status(400).json({
        success: false,
        message: 'Invalid checker. User must have checker role.'
      });
    }
    
    // Update workflow
    proposal.workflow.maker.status = 'submitted';
    proposal.workflow.maker.submittedAt = new Date();
    proposal.workflow.maker.comments = comments || '';
    proposal.workflow.checker.userId = checkerId;
    proposal.workflow.checker.status = 'pending';
    proposal.workflow.currentStage = 'checker';
    
    await proposal.save();
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: proposal.companyId,
      action: 'review',
      module: 'proposals',
      entityType: 'Proposal',
      entityId: proposal._id,
      description: `Submitted proposal for review: ${proposal.proposalNumber}`,
      changes: { workflowStage: 'checker', checkerId },
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    const populatedProposal = await Proposal.findById(proposal._id)
      .populate('companyId', 'name code')
      .populate('workflow.maker.userId', 'firstName lastName')
      .populate('workflow.checker.userId', 'firstName lastName');
    
    res.status(200).json({
      success: true,
      message: 'Proposal submitted for review successfully',
      data: populatedProposal
    });
  } catch (error) {
    next(error);
  }
};

// Review proposal (Checker)
exports.reviewProposal = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { action, verifierId, comments } = req.body;
    
    const proposal = await Proposal.findById(id);
    
    if (!proposal) {
      return res.status(404).json({
        success: false,
        message: 'Proposal not found'
      });
    }
    
    // Verify user is the assigned checker
    if (proposal.workflow.checker.userId.toString() !== req.user._id.toString()) {
      return res.status(403).json({
        success: false,
        message: 'You are not assigned as checker for this proposal'
      });
    }
    
    if (action === 'forward') {
      const verifier = await User.findById(verifierId).populate('roleId');
      if (!verifier || verifier.roleId.name !== 'verifier') {
        return res.status(400).json({
          success: false,
          message: 'Invalid verifier. User must have verifier role.'
        });
      }
      
      proposal.workflow.checker.status = 'forwarded';
      proposal.workflow.checker.reviewedAt = new Date();
      proposal.workflow.checker.comments = comments || '';
      proposal.workflow.verifier.userId = verifierId;
      proposal.workflow.verifier.status = 'pending';
      proposal.workflow.currentStage = 'verifier';
      
    } else if (action === 'send_back') {
      proposal.workflow.checker.status = 'sent_back';
      proposal.workflow.checker.reviewedAt = new Date();
      proposal.workflow.checker.comments = comments || '';
      proposal.workflow.maker.status = 'rejected';
      proposal.workflow.currentStage = 'maker';
    } else {
      return res.status(400).json({
        success: false,
        message: 'Invalid action. Must be: forward or send_back'
      });
    }
    
    await proposal.save();
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: proposal.companyId,
      action: 'review',
      module: 'proposals',
      entityType: 'Proposal',
      entityId: proposal._id,
      description: `Checker ${action === 'forward' ? 'forwarded to verifier' : 'sent back to maker'}: ${proposal.proposalNumber}`,
      changes: { action, comments },
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    const populatedProposal = await Proposal.findById(proposal._id)
      .populate('companyId', 'name code')
      .populate('workflow.maker.userId', 'firstName lastName')
      .populate('workflow.checker.userId', 'firstName lastName')
      .populate('workflow.verifier.userId', 'firstName lastName');
    
    res.status(200).json({
      success: true,
      message: `Proposal ${action === 'forward' ? 'forwarded to verifier' : 'sent back to maker'} successfully`,
      data: populatedProposal
    });
  } catch (error) {
    next(error);
  }
};

// Approve/Reject proposal (Verifier)
exports.verifyProposal = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { action, comments } = req.body;
    
    const proposal = await Proposal.findById(id);
    
    if (!proposal) {
      return res.status(404).json({
        success: false,
        message: 'Proposal not found'
      });
    }
    
    // Verify user is the assigned verifier
    if (proposal.workflow.verifier.userId.toString() !== req.user._id.toString()) {
      return res.status(403).json({
        success: false,
        message: 'You are not assigned as verifier for this proposal'
      });
    }
    
    if (action === 'approve') {
      proposal.workflow.verifier.status = 'approved';
      proposal.workflow.verifier.approvedAt = new Date();
      proposal.workflow.verifier.comments = comments || '';
      proposal.workflow.currentStage = 'completed';
      proposal.status = 'sent';
      proposal.sentDate = new Date();
      
    } else if (action === 'reject') {
      proposal.workflow.verifier.status = 'rejected';
      proposal.workflow.verifier.approvedAt = new Date();
      proposal.workflow.verifier.comments = comments || '';
      proposal.workflow.currentStage = 'completed';
      proposal.status = 'rejected';
      proposal.rejectedDate = new Date();
      proposal.rejectionReason = comments;
      
    } else if (action === 'send_back') {
      proposal.workflow.verifier.status = 'sent_back';
      proposal.workflow.verifier.approvedAt = new Date();
      proposal.workflow.verifier.comments = comments || '';
      proposal.workflow.checker.status = 'pending';
      proposal.workflow.currentStage = 'checker';
    } else {
      return res.status(400).json({
        success: false,
        message: 'Invalid action. Must be: approve, reject, or send_back'
      });
    }
    
    await proposal.save();
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: proposal.companyId,
      action: action === 'approve' ? 'approve' : 'reject',
      module: 'proposals',
      entityType: 'Proposal',
      entityId: proposal._id,
      description: `Verifier ${action}d proposal: ${proposal.proposalNumber}`,
      changes: { action, comments },
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    const populatedProposal = await Proposal.findById(proposal._id)
      .populate('companyId', 'name code')
      .populate('workflow.maker.userId', 'firstName lastName')
      .populate('workflow.checker.userId', 'firstName lastName')
      .populate('workflow.verifier.userId', 'firstName lastName');
    
    res.status(200).json({
      success: true,
      message: `Proposal ${action}d successfully`,
      data: populatedProposal
    });
  } catch (error) {
    next(error);
  }
};

// Customer accepts/rejects proposal
exports.customerResponse = async (req, res, next) => {
  try {
    const { id } = req.params;
    const { action, reason } = req.body; // action: 'accept' | 'reject'
    
    const proposal = await Proposal.findById(id);
    
    if (!proposal) {
      return res.status(404).json({
        success: false,
        message: 'Proposal not found'
      });
    }
    
    if (proposal.status !== 'sent' && proposal.status !== 'viewed') {
      return res.status(400).json({
        success: false,
        message: 'Proposal must be in sent/viewed status'
      });
    }
    
    if (action === 'accept') {
      proposal.status = 'accepted';
      proposal.acceptedDate = new Date();
    } else if (action === 'reject') {
      proposal.status = 'rejected';
      proposal.rejectedDate = new Date();
      proposal.rejectionReason = reason;
    } else {
      return res.status(400).json({
        success: false,
        message: 'Invalid action. Must be: accept or reject'
      });
    }
    
    await proposal.save();
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: proposal.companyId,
      action: action === 'accept' ? 'approve' : 'reject',
      module: 'proposals',
      entityType: 'Proposal',
      entityId: proposal._id,
      description: `Customer ${action}ed proposal: ${proposal.proposalNumber}`,
      changes: { action, reason },
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    res.status(200).json({
      success: true,
      message: `Proposal ${action}ed successfully`,
      data: proposal
    });
  } catch (error) {
    next(error);
  }
};

// Mark proposal as viewed
exports.markAsViewed = async (req, res, next) => {
  try {
    const { id } = req.params;
    
    const proposal = await Proposal.findById(id);
    
    if (!proposal) {
      return res.status(404).json({
        success: false,
        message: 'Proposal not found'
      });
    }
    
    if (proposal.status === 'sent' && !proposal.viewedDate) {
      proposal.status = 'viewed';
      proposal.viewedDate = new Date();
      await proposal.save();
      
      // Log activity
      await ActivityLog.create({
        userId: req.user._id,
        companyId: proposal.companyId,
        action: 'update',
        module: 'proposals',
        entityType: 'Proposal',
        entityId: proposal._id,
        description: `Proposal viewed: ${proposal.proposalNumber}`,
        ipAddress: req.ip,
        userAgent: req.get('user-agent')
      });
    }
    
    res.status(200).json({
      success: true,
      message: 'Proposal marked as viewed',
      data: proposal
    });
  } catch (error) {
    next(error);
  }
};

// Get proposal statistics
exports.getProposalStats = async (req, res, next) => {
  try {
    const { companyId } = req.query;
    
    let query = {};
    
    const userRole = await Role.findById(req.user.roleId);
    if (userRole.scope !== 'global') {
      query.companyId = req.user.companyId;
    } else if (companyId) {
      query.companyId = companyId;
    }
    
    const totalProposals = await Proposal.countDocuments(query);
    
    // By status
    const byStatus = await Proposal.aggregate([
      { $match: query },
      {
        $group: {
          _id: '$status',
          count: { $sum: 1 },
          totalValue: { $sum: '$pricing.total' }
        }
      }
    ]);
    
    // By priority
    const byPriority = await Proposal.aggregate([
      { $match: query },
      {
        $group: {
          _id: '$priority',
          count: { $sum: 1 }
        }
      }
    ]);
    
    // By workflow stage
    const byWorkflowStage = await Proposal.aggregate([
      { $match: query },
      {
        $group: {
          _id: '$workflow.currentStage',
          count: { $sum: 1 }
        }
      }
    ]);
    
    // Total value
    const totalValue = await Proposal.aggregate([
      { $match: query },
      {
        $group: {
          _id: null,
          total: { $sum: '$pricing.total' }
        }
      }
    ]);
    
    // Conversion rate
    const acceptedCount = await Proposal.countDocuments({ ...query, status: 'accepted' });
    const sentCount = await Proposal.countDocuments({ 
      ...query, 
      status: { $in: ['sent', 'viewed', 'accepted', 'rejected'] } 
    });
    const conversionRate = sentCount > 0 ? ((acceptedCount / sentCount) * 100).toFixed(2) : 0;
    
    res.status(200).json({
      success: true,
      data: {
        total: totalProposals,
        totalValue: totalValue[0]?.total || 0,
        conversionRate: parseFloat(conversionRate),
        accepted: acceptedCount,
        byStatus,
        byPriority,
        byWorkflowStage
      }
    });
  } catch (error) {
    next(error);
  }
};

// Clone/Duplicate proposal
exports.cloneProposal = async (req, res, next) => {
  try {
    const { id } = req.params;
    
    const originalProposal = await Proposal.findById(id);
    
    if (!originalProposal) {
      return res.status(404).json({
        success: false,
        message: 'Proposal not found'
      });
    }
    
    // Create new proposal with same data
    const proposalData = originalProposal.toObject();
    delete proposalData._id;
    delete proposalData.proposalNumber;
    delete proposalData.createdAt;
    delete proposalData.updatedAt;
    delete proposalData.sentDate;
    delete proposalData.viewedDate;
    delete proposalData.acceptedDate;
    delete proposalData.rejectedDate;
    
    proposalData.status = 'draft';
    proposalData.title = `${proposalData.title} (Copy)`;
    proposalData.workflow = {
      currentStage: 'maker',
      maker: {
        userId: req.user._id,
        status: 'draft'
      }
    };
    proposalData.createdBy = req.user._id;
    
    const newProposal = await Proposal.create(proposalData);
    
    // Log activity
    await ActivityLog.create({
      userId: req.user._id,
      companyId: newProposal.companyId,
      action: 'create',
      module: 'proposals',
      entityType: 'Proposal',
      entityId: newProposal._id,
      description: `Cloned proposal from: ${originalProposal.proposalNumber}`,
      ipAddress: req.ip,
      userAgent: req.get('user-agent')
    });
    
    const populatedProposal = await Proposal.findById(newProposal._id)
      .populate('companyId', 'name code')
      .populate('createdBy', 'firstName lastName email');
    
    res.status(201).json({
      success: true,
      message: 'Proposal cloned successfully',
      data: populatedProposal
    });
  } catch (error) {
    next(error);
  }
};