const nocodbService = require('../services/nocodb');
const { validateResponse } = require('../utils/validators');

/**
 * Get all responses for a campaign
 * Public endpoint - no authentication required
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function getCampaignResponses(req, res) {
  try {
    const { slug } = req.params;
    const { sort = 'recent', level = '', offset = 0, limit = 20, status = 'approved' } = req.query;

    // Get campaign by slug first
    const campaign = await nocodbService.getCampaignBySlug(slug);
    if (!campaign) {
      return res.status(404).json({ error: 'Campaign not found' });
    }

    // Build filter conditions
    // NocoDB v2 API requires ~and operator between multiple conditions
    let whereConditions = [
      `(Campaign Slug,eq,${slug})~and(Status,eq,${status})`
    ];

    if (level) {
      whereConditions[0] += `~and(Representative Level,eq,${level})`;
    }

    // Build sort order
    let sortOrder = '-CreatedAt'; // Default to most recent
    if (sort === 'upvotes') {
      sortOrder = '-Upvote Count';
    } else if (sort === 'verified') {
      sortOrder = '-Is Verified,-CreatedAt';
    }

    // Fetch responses
    const responses = await nocodbService.getRepresentativeResponses({
      where: whereConditions[0],  // Use the first (and only) element
      sort: sortOrder,
      offset: parseInt(offset),
      limit: parseInt(limit)
    });

    console.log(`Found ${responses.length} responses for campaign ${slug} with status ${status}`);
    if (responses.length > 0) {
      console.log('First response sample:', JSON.stringify(responses[0], null, 2));
    }

    // For each response, check if current user has upvoted
    const userId = req.user?.id;
    const userEmail = req.user?.email;
    
    const responsesWithUpvoteStatus = await Promise.all(responses.map(async (response) => {
      let hasUpvoted = false;
      
      if (userId || userEmail) {
        const upvotes = await nocodbService.getResponseUpvotes({
          where: `(Response ID,eq,${response.id})`
        });
        
        hasUpvoted = upvotes.some(upvote => 
          (userId && upvote.user_id === userId) || 
          (userEmail && upvote.user_email === userEmail)
        );
      }
      
      return {
        ...response,
        hasUpvoted
      };
    }));

    res.json({
      success: true,
      responses: responsesWithUpvoteStatus,
      pagination: {
        offset: parseInt(offset),
        limit: parseInt(limit),
        hasMore: responses.length === parseInt(limit)
      }
    });

  } catch (error) {
    console.error('Error getting campaign responses:', error);
    res.status(500).json({ error: 'Failed to get campaign responses' });
  }
}

/**
 * Submit a new response
 * Optional authentication - allows anonymous submissions
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function submitResponse(req, res) {
  try {
    const { slug } = req.params;
    const responseData = req.body;

    // Get campaign by slug first
    const campaign = await nocodbService.getCampaignBySlug(slug);
    if (!campaign) {
      return res.status(404).json({ error: 'Campaign not found' });
    }

    // Validate response data
    const validation = validateResponse(responseData);
    if (!validation.valid) {
      return res.status(400).json({ error: validation.error });
    }

    // Handle file upload if present
    let screenshotUrl = null;
    if (req.file) {
      screenshotUrl = `/uploads/responses/${req.file.filename}`;
    }

    // Prepare response data for NocoDB
    const newResponse = {
      campaign_id: campaign.ID || campaign.Id || campaign.id || campaign['Campaign ID'],
      campaign_slug: slug,
      representative_name: responseData.representative_name,
      representative_title: responseData.representative_title || null,
      representative_level: responseData.representative_level,
      response_type: responseData.response_type,
      response_text: responseData.response_text,
      user_comment: responseData.user_comment || null,
      screenshot_url: screenshotUrl,
      submitted_by_name: responseData.submitted_by_name || null,
      submitted_by_email: responseData.submitted_by_email || null,
      submitted_by_user_id: req.user?.id || null,
      is_anonymous: responseData.is_anonymous || false,
      status: 'pending', // All submissions start as pending
      is_verified: false,
      upvote_count: 0,
      submitted_ip: req.ip || req.connection.remoteAddress
    };
    
    console.log('Submitting response with campaign_id:', newResponse.campaign_id, 'from campaign:', campaign);

    // Create response in database
    const createdResponse = await nocodbService.createRepresentativeResponse(newResponse);

    res.status(201).json({
      success: true,
      message: 'Response submitted successfully. It will be visible after moderation.',
      response: createdResponse
    });

  } catch (error) {
    console.error('Error submitting response:', error);
    res.status(500).json({ error: 'Failed to submit response' });
  }
}

/**
 * Upvote a response
 * Optional authentication - allows anonymous upvotes with IP tracking
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function upvoteResponse(req, res) {
  try {
    const { id } = req.params;

    // Get response
    const response = await nocodbService.getRepresentativeResponseById(id);
    if (!response) {
      return res.status(404).json({ error: 'Response not found' });
    }

    const userId = req.user?.id;
    const userEmail = req.user?.email;
    const userIp = req.ip || req.connection.remoteAddress;

    // Check if already upvoted
    const existingUpvotes = await nocodbService.getResponseUpvotes({
      where: `(Response ID,eq,${id})`
    });

    const alreadyUpvoted = existingUpvotes.some(upvote => 
      (userId && upvote.user_id === userId) || 
      (userEmail && upvote.user_email === userEmail) ||
      (upvote.upvoted_ip === userIp)
    );

    if (alreadyUpvoted) {
      return res.status(400).json({ error: 'You have already upvoted this response' });
    }

    // Create upvote
    await nocodbService.createResponseUpvote({
      response_id: id,
      user_id: userId || null,
      user_email: userEmail || null,
      upvoted_ip: userIp
    });

    // Increment upvote count
    const newCount = (response.upvote_count || 0) + 1;
    await nocodbService.updateRepresentativeResponse(id, {
      upvote_count: newCount
    });

    res.json({
      success: true,
      message: 'Response upvoted successfully',
      upvoteCount: newCount
    });

  } catch (error) {
    console.error('Error upvoting response:', error);
    res.status(500).json({ error: 'Failed to upvote response' });
  }
}

/**
 * Remove upvote from a response
 * Optional authentication
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function removeUpvote(req, res) {
  try {
    const { id } = req.params;

    // Get response
    const response = await nocodbService.getRepresentativeResponseById(id);
    if (!response) {
      return res.status(404).json({ error: 'Response not found' });
    }

    const userId = req.user?.id;
    const userEmail = req.user?.email;
    const userIp = req.ip || req.connection.remoteAddress;

    // Find upvote to remove
    const upvotes = await nocodbService.getResponseUpvotes({
      where: `(Response ID,eq,${id})`
    });

    const upvoteToRemove = upvotes.find(upvote => 
      (userId && upvote.user_id === userId) || 
      (userEmail && upvote.user_email === userEmail) ||
      (upvote.upvoted_ip === userIp)
    );

    if (!upvoteToRemove) {
      return res.status(400).json({ error: 'You have not upvoted this response' });
    }

    // Delete upvote
    await nocodbService.deleteResponseUpvote(upvoteToRemove.id);

    // Decrement upvote count
    const newCount = Math.max((response.upvote_count || 0) - 1, 0);
    await nocodbService.updateRepresentativeResponse(id, {
      upvote_count: newCount
    });

    res.json({
      success: true,
      message: 'Upvote removed successfully',
      upvoteCount: newCount
    });

  } catch (error) {
    console.error('Error removing upvote:', error);
    res.status(500).json({ error: 'Failed to remove upvote' });
  }
}

/**
 * Get response statistics for a campaign
 * Public endpoint
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function getResponseStats(req, res) {
  try {
    const { slug } = req.params;

    // Get campaign by slug first
    const campaign = await nocodbService.getCampaignBySlug(slug);
    if (!campaign) {
      return res.status(404).json({ error: 'Campaign not found' });
    }

    // Get all approved responses for this campaign
    const responses = await nocodbService.getRepresentativeResponses({
      where: `(Campaign Slug,eq,${slug}),(Status,eq,approved)`
    });

    // Calculate stats
    const totalResponses = responses.length;
    const verifiedResponses = responses.filter(r => r.is_verified).length;
    const totalUpvotes = responses.reduce((sum, r) => sum + (r.upvote_count || 0), 0);

    // Count by level
    const byLevel = {
      Federal: responses.filter(r => r.representative_level === 'Federal').length,
      Provincial: responses.filter(r => r.representative_level === 'Provincial').length,
      Municipal: responses.filter(r => r.representative_level === 'Municipal').length,
      'School Board': responses.filter(r => r.representative_level === 'School Board').length
    };

    res.json({
      success: true,
      stats: {
        totalResponses,
        verifiedResponses,
        totalUpvotes,
        byLevel
      }
    });

  } catch (error) {
    console.error('Error getting response stats:', error);
    res.status(500).json({ error: 'Failed to get response statistics' });
  }
}

// Admin functions

/**
 * Get all responses (admin only - includes pending/rejected)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function getAdminResponses(req, res) {
  try {
    const { status = 'all', offset = 0, limit = 50 } = req.query;

    console.log(`Admin fetching responses with status filter: ${status}`);

    let whereConditions = [];
    if (status !== 'all') {
      whereConditions.push(`(Status,eq,${status})`);
    }

    const responses = await nocodbService.getRepresentativeResponses({
      where: whereConditions.join(','),
      sort: '-CreatedAt',
      offset: parseInt(offset),
      limit: parseInt(limit)
    });

    console.log(`Admin found ${responses.length} total responses`);
    if (responses.length > 0) {
      console.log('Response statuses:', responses.map(r => `ID:${r.id} Status:${r.status}`).join(', '));
    }

    res.json({
      success: true,
      responses,
      pagination: {
        offset: parseInt(offset),
        limit: parseInt(limit),
        hasMore: responses.length === parseInt(limit)
      }
    });

  } catch (error) {
    console.error('Error getting admin responses:', error);
    res.status(500).json({ error: 'Failed to get responses' });
  }
}

/**
 * Update response status (admin only)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function updateResponseStatus(req, res) {
  try {
    const { id } = req.params;
    const { status } = req.body;

    console.log(`Updating response ${id} to status: ${status}`);

    if (!['pending', 'approved', 'rejected'].includes(status)) {
      return res.status(400).json({ error: 'Invalid status' });
    }

    const updated = await nocodbService.updateRepresentativeResponse(id, { status });
    console.log('Updated response:', JSON.stringify(updated, null, 2));

    res.json({
      success: true,
      message: `Response ${status} successfully`
    });

  } catch (error) {
    console.error('Error updating response status:', error);
    res.status(500).json({ error: 'Failed to update response status' });
  }
}

/**
 * Update response (admin only)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function updateResponse(req, res) {
  try {
    const { id } = req.params;
    const updates = req.body;

    await nocodbService.updateRepresentativeResponse(id, updates);

    res.json({
      success: true,
      message: 'Response updated successfully'
    });

  } catch (error) {
    console.error('Error updating response:', error);
    res.status(500).json({ error: 'Failed to update response' });
  }
}

/**
 * Delete response (admin only)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
async function deleteResponse(req, res) {
  try {
    const { id } = req.params;

    // Delete all upvotes for this response first
    const upvotes = await nocodbService.getResponseUpvotes({
      where: `(Response ID,eq,${id})`
    });

    for (const upvote of upvotes) {
      await nocodbService.deleteResponseUpvote(upvote.id);
    }

    // Delete the response
    await nocodbService.deleteRepresentativeResponse(id);

    res.json({
      success: true,
      message: 'Response deleted successfully'
    });

  } catch (error) {
    console.error('Error deleting response:', error);
    res.status(500).json({ error: 'Failed to delete response' });
  }
}

module.exports = {
  getCampaignResponses,
  submitResponse,
  upvoteResponse,
  removeUpvote,
  getResponseStats,
  getAdminResponses,
  updateResponseStatus,
  updateResponse,
  deleteResponse
};
