const express = require('express');
const { v4: uuidv4 } = require('uuid');
const router = express.Router();
const emailService = require('../services/emailService');

module.exports = (pool, query, authMiddleware) => {
  
  /**
   * Public route to handle subscription
   * POST /api/subscribers/subscribe
   */
  router.post('/subscribe', async (req, res, next) => {
    try {
      const { email, firstName, lastName, listId } = req.body;
      
      // Validate required fields
      if (!email || !listId) {
        return res.status(400).json({
          error: true,
          message: 'Email and list ID are required'
        });
      }
      
      // Check if list exists
      const listCheck = await query(
        'SELECT id FROM mailing_lists WHERE id = $1',
        [listId]
      );
      
      if (listCheck.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Mailing list not found'
        });
      }
      
      // Begin transaction
      const client = await pool.connect();
      
      try {
        await client.query('BEGIN');
        
        // Check if subscriber already exists
        let subscriberId;
        const subscriberCheck = await client.query(
          'SELECT id, status FROM subscribers WHERE email = $1',
          [email]
        );
        
        if (subscriberCheck.rows.length > 0) {
          // Update existing subscriber
          subscriberId = subscriberCheck.rows[0].id;
          const currentStatus = subscriberCheck.rows[0].status;
          
          // Only update if not already unsubscribed or complained
          if (currentStatus !== 'unsubscribed' && currentStatus !== 'complained') {
            await client.query(
              `UPDATE subscribers
               SET first_name = COALESCE($1, first_name),
                   last_name = COALESCE($2, last_name),
                   status = 'active',
                   updated_at = NOW()
               WHERE id = $3`,
              [firstName, lastName, subscriberId]
            );
          } else {
            await client.query('ROLLBACK');
            return res.status(400).json({
              error: true,
              message: 'This email has previously unsubscribed and cannot be resubscribed without consent'
            });
          }
        } else {
          // Create new subscriber
          subscriberId = uuidv4();
          await client.query(
            `INSERT INTO subscribers (id, email, first_name, last_name)
             VALUES ($1, $2, $3, $4)`,
            [subscriberId, email, firstName, lastName]
          );
        }
        
        // Check if subscriber is already on this list
        const listSubscriberCheck = await client.query(
          'SELECT * FROM mailing_list_subscribers WHERE list_id = $1 AND subscriber_id = $2',
          [listId, subscriberId]
        );
        
        if (listSubscriberCheck.rows.length === 0) {
          // Add subscriber to list
          await client.query(
            `INSERT INTO mailing_list_subscribers (list_id, subscriber_id)
             VALUES ($1, $2)`,
            [listId, subscriberId]
          );
        }
        
        await client.query('COMMIT');
        
        // Generate a confirmation token for double opt-in
        const confirmationToken = uuidv4();
        
        // Store the confirmation token
        await query(
          `INSERT INTO subscription_confirmations (subscriber_id, token, expires_at)
           VALUES ($1, $2, NOW() + INTERVAL '7 days')`,
          [subscriberId, confirmationToken]
        );
        
        // Send confirmation email
        try {
          await emailService.sendSubscriptionConfirmation({
            to: email,
            firstName: firstName || '',
            confirmationLink: `${process.env.SITE_URL}/confirm-subscription?token=${confirmationToken}`
          });
        } catch (emailError) {
          console.error('Failed to send confirmation email:', emailError);
        }
        
        res.status(200).json({
          success: true,
          message: 'Subscription request received. Please check your email to confirm your subscription.'
        });
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    } catch (error) {
      next(error);
    }
  });
  
  /**
   * Confirm subscription (double opt-in)
   * GET /api/subscribers/confirm
   */
  router.get('/confirm', async (req, res, next) => {
    try {
      const { token } = req.query;
      
      if (!token) {
        return res.status(400).json({
          error: true,
          message: 'Confirmation token is required'
        });
      }
      
      // Check if token exists and is valid
      const confirmationQuery = `
        SELECT 
          sc.subscriber_id,
          s.email,
          s.first_name
        FROM subscription_confirmations sc
        JOIN subscribers s ON sc.subscriber_id = s.id
        WHERE sc.token = $1 AND sc.expires_at > NOW() AND sc.confirmed_at IS NULL
      `;
      
      const confirmationResult = await query(confirmationQuery, [token]);
      
      if (confirmationResult.rows.length === 0) {
        return res.status(400).json({
          error: true,
          message: 'Invalid or expired confirmation token'
        });
      }
      
      const { subscriber_id, email, first_name } = confirmationResult.rows[0];
      
      // Mark subscription as confirmed
      await query(
        `UPDATE subscription_confirmations
         SET confirmed_at = NOW()
         WHERE token = $1`,
        [token]
      );
      
      // Ensure subscriber is marked as active
      await query(
        `UPDATE subscribers
         SET status = 'active', updated_at = NOW()
         WHERE id = $1`,
        [subscriber_id]
      );
      
      // Send welcome email
      try {
        await emailService.sendWelcomeEmail({
          to: email,
          firstName: first_name || ''
        });
      } catch (emailError) {
        console.error('Failed to send welcome email:', emailError);
      }
      
      res.status(200).json({
        success: true,
        message: 'Your subscription has been confirmed. Thank you!'
      });
    } catch (error) {
      next(error);
    }
  });
  
  /**
   * Handle unsubscribe request
   * GET /api/subscribers/unsubscribe
   */
  router.get('/unsubscribe', async (req, res, next) => {
    try {
      const { email, token, listId } = req.query;
      
      if (!email && !token) {
        return res.status(400).json({
          error: true,
          message: 'Email or token is required'
        });
      }
      
      // Begin transaction
      const client = await pool.connect();
      
      try {
        await client.query('BEGIN');
        
        let subscriberId;
        
        if (token) {
          // Verify the unsubscribe token
          const tokenCheck = await client.query(
            'SELECT subscriber_id FROM unsubscribe_tokens WHERE token = $1 AND expires_at > NOW()',
            [token]
          );
          
          if (tokenCheck.rows.length === 0) {
            await client.query('ROLLBACK');
            return res.status(400).json({
              error: true,
              message: 'Invalid or expired unsubscribe token'
            });
          }
          
          subscriberId = tokenCheck.rows[0].subscriber_id;
        } else {
          // Look up subscriber by email
          const subscriberCheck = await client.query(
            'SELECT id FROM subscribers WHERE email = $1',
            [email]
          );
          
          if (subscriberCheck.rows.length === 0) {
            await client.query('ROLLBACK');
            return res.status(404).json({
              error: true,
              message: 'Email not found in our database'
            });
          }
          
          subscriberId = subscriberCheck.rows[0].id;
        }
        
        // Update subscriber status
        await client.query(
          `UPDATE subscribers
           SET status = 'unsubscribed', updated_at = NOW()
           WHERE id = $1`,
          [subscriberId]
        );
        
        // If list ID is provided, only remove from that list
        if (listId) {
          await client.query(
            'DELETE FROM mailing_list_subscribers WHERE subscriber_id = $1 AND list_id = $2',
            [subscriberId, listId]
          );
        } 
        // Otherwise remove from all lists
        else {
          await client.query(
            'DELETE FROM mailing_list_subscribers WHERE subscriber_id = $1',
            [subscriberId]
          );
        }
        
        // Record unsubscribe activity
        await client.query(
          `INSERT INTO subscriber_activity (subscriber_id, type, details)
           VALUES ($1, 'unsubscribe', $2)`,
          [subscriberId, listId ? `Unsubscribed from list ${listId}` : 'Unsubscribed from all lists']
        );
        
        await client.query('COMMIT');
        
        res.status(200).json({
          success: true,
          message: 'You have been successfully unsubscribed'
        });
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    } catch (error) {
      next(error);
    }
  });
  
  /**
   * Public route to handle bounce and complaint notifications
   * POST /api/subscribers/webhook
   */
  router.post('/webhook', async (req, res, next) => {
    try {
      const { type, email, message, campaignId, reason, timestamp } = req.body;
      
      // Validate required fields
      if (!type || !email) {
        return res.status(400).json({
          error: true,
          message: 'Type and email are required'
        });
      }
      
      // Verify webhook signature
      // In production, implement proper verification of webhook authenticity
      
      // Find subscriber by email
      const subscriberCheck = await query(
        'SELECT id FROM subscribers WHERE email = $1',
        [email]
      );
      
      if (subscriberCheck.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Subscriber not found'
        });
      }
      
      const subscriberId = subscriberCheck.rows[0].id;
      
      // Handle event based on type
      switch (type) {
        case 'bounce':
          // Update subscriber status
          await query(
            `UPDATE subscribers
             SET status = 'bounced', updated_at = NOW()
             WHERE id = $1`,
            [subscriberId]
          );
          
          // Record bounce activity
          await query(
            `INSERT INTO subscriber_activity (subscriber_id, campaign_id, type, timestamp, details)
             VALUES ($1, $2, 'bounce', $3, $4)`,
            [subscriberId, campaignId, timestamp || new Date(), reason || message || 'Email bounced']
          );
          break;
          
        case 'complaint':
          // Update subscriber status
          await query(
            `UPDATE subscribers
             SET status = 'complained', updated_at = NOW()
             WHERE id = $1`,
            [subscriberId]
          );
          
          // Remove from all lists
          await query(
            'DELETE FROM mailing_list_subscribers WHERE subscriber_id = $1',
            [subscriberId]
          );
          
          // Record complaint activity
          await query(
            `INSERT INTO subscriber_activity (subscriber_id, campaign_id, type, timestamp, details)
             VALUES ($1, $2, 'complaint', $3, $4)`,
            [subscriberId, campaignId, timestamp || new Date(), reason || message || 'Spam complaint received']
          );
          break;
          
        default:
          return res.status(400).json({
            error: true,
            message: 'Unsupported event type'
          });
      }
      
      res.json({
        success: true,
        message: `Processed ${type} for ${email}`
      });
    } catch (error) {
      next(error);
    }
  });


  router.use(authMiddleware);
  
  /**
   * Update a subscriber (admin)
   * PUT /api/subscribers/:id
   */
  router.put('/:id', async (req, res, next) => {
    try {
      const { id } = req.params;
      const { email, firstName, lastName, status } = req.body;
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Validate required fields
      if (!email) {
        return res.status(400).json({
          error: true,
          message: 'Email is required'
        });
      }
      
      // Check if subscriber exists
      const subscriberCheck = await query(
        'SELECT id FROM subscribers WHERE id = $1',
        [id]
      );
      
      if (subscriberCheck.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Subscriber not found'
        });
      }
      
      // Update subscriber
      const result = await query(
        `UPDATE subscribers
         SET email = $1,
             first_name = $2,
             last_name = $3,
             status = $4,
             updated_at = NOW()
         WHERE id = $5
         RETURNING *`,
        [email, firstName, lastName, status, id]
      );
      
      res.json(result.rows[0]);
    } catch (error) {
      next(error);
    }
  });
  
  /**
   * Delete a subscriber (admin)
   * DELETE /api/subscribers/:id
   */
  router.delete('/:id', async (req, res, next) => {
    try {
      const { id } = req.params;
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Check if subscriber exists
      const subscriberCheck = await query(
        'SELECT id FROM subscribers WHERE id = $1',
        [id]
      );
      
      if (subscriberCheck.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Subscriber not found'
        });
      }
      
      // Begin transaction
      const client = await pool.connect();
      
      try {
        await client.query('BEGIN');
        
        // Remove from all mailing lists
        await client.query(
          'DELETE FROM mailing_list_subscribers WHERE subscriber_id = $1',
          [id]
        );
        
        // Delete subscriber
        await client.query(
          'DELETE FROM subscribers WHERE id = $1',
          [id]
        );
        
        await client.query('COMMIT');
        
        res.json({
          success: true,
          message: 'Subscriber deleted successfully'
        });
      } catch (error) {
        await client.query('ROLLBACK');
        throw error;
      } finally {
        client.release();
      }
    } catch (error) {
      next(error);
    }
  });
  
  /**
   * Get subscriber activity (admin)
   * GET /api/subscribers/:id/activity
   */
  router.get('/:id/activity', async (req, res, next) => {
    try {
      const { id } = req.params;
      
      if (!req.user.is_admin) {
        return res.status(403).json({
          error: true,
          message: 'Admin access required'
        });
      }
      
      // Check if subscriber exists
      const subscriberCheck = await query(
        'SELECT id FROM subscribers WHERE id = $1',
        [id]
      );
      
      if (subscriberCheck.rows.length === 0) {
        return res.status(404).json({
          error: true,
          message: 'Subscriber not found'
        });
      }
      
      // Get subscriber activity
      const activityQuery = `
        SELECT 
          sa.id,
          sa.campaign_id,
          ec.name as campaign_name,
          sa.type,
          sa.timestamp,
          sa.details
        FROM subscriber_activity sa
        LEFT JOIN email_campaigns ec ON sa.campaign_id = ec.id
        WHERE sa.subscriber_id = $1
        ORDER BY sa.timestamp DESC
      `;
      
      const activityResult = await query(activityQuery, [id]);
      
      res.json(activityResult.rows);
    } catch (error) {
      next(error);
    }
  });
  
  
  return router;
};