const jwt = require('jsonwebtoken');
const { db } = require('../database/db');
const { formatBoolean } = require('../utils/dbCompat');
const logger = require('../utils/logger');

/**
 * Enhanced admin authentication middleware
 * Adds additional security checks beyond basic JWT validation
 */
async function adminAuth(req, res, next) {
  try {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) {
      return res.status(401).json({ error: 'No token provided' });
    }
    
    let decoded;
    try {
      decoded = jwt.verify(token, process.env.JWT_SECRET, {
        issuer: 'picpeak-auth',
        complete: true
      });
      decoded = decoded.payload; // Extract payload when using complete: true
    } catch (err) {
      if (err.name === 'TokenExpiredError') {
        return res.status(401).json({ error: 'Token expired', code: 'TOKEN_EXPIRED' });
      }
      return res.status(401).json({ error: 'Invalid token' });
    }
    
    // Verify token type
    if (decoded.type !== 'admin') {
      logger.warn('Non-admin token used for admin endpoint', { 
        userId: decoded.id,
        tokenType: decoded.type 
      });
      return res.status(403).json({ error: 'Insufficient permissions' });
    }
    
    // IP validation (optional - can be strict or just log)
    const currentIp = req.ip || req.connection.remoteAddress;
    if (decoded.ip && decoded.ip !== currentIp) {
      logger.warn('Token used from different IP', {
        userId: decoded.id,
        tokenIp: decoded.ip,
        currentIp: currentIp
      });
      // Optional: Reject if IP doesn't match
      // return res.status(401).json({ error: 'Invalid token' });
    }
    
    // Check if admin still exists and is active
    const admin = await db('admin_users')
      .where({ id: decoded.id, is_active: formatBoolean(true) })
      .first();
    
    if (!admin) {
      return res.status(401).json({ error: 'Invalid token' });
    }
    
    // Check if password was changed after token was issued
    if (admin.password_changed_at) {
      const passwordChangedTime = new Date(admin.password_changed_at).getTime() / 1000;
      if (decoded.iat < passwordChangedTime) {
        logger.warn('Token used after password change', { userId: decoded.id });
        return res.status(401).json({ 
          error: 'Token invalid due to password change',
          code: 'PASSWORD_CHANGED'
        });
      }
    }
    
    // Add user info to request
    req.admin = {
      id: admin.id,
      username: admin.username,
      email: admin.email
    };
    
    next();
  } catch (error) {
    logger.error('Auth middleware error:', error);
    res.status(401).json({ error: 'Authentication failed' });
  }
}

/**
 * Enhanced gallery authentication middleware
 */
async function galleryAuth(req, res, next) {
  try {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) {
      return res.status(401).json({ error: 'No token provided' });
    }
    
    let decoded;
    try {
      decoded = jwt.verify(token, process.env.JWT_SECRET, {
        issuer: 'picpeak-auth',
        complete: true
      });
      decoded = decoded.payload;
    } catch (err) {
      if (err.name === 'TokenExpiredError') {
        return res.status(401).json({ error: 'Session expired', code: 'TOKEN_EXPIRED' });
      }
      return res.status(401).json({ error: 'Invalid session' });
    }
    
    // Verify token type
    if (decoded.type !== 'gallery') {
      return res.status(403).json({ error: 'Invalid access token' });
    }
    
    // Check if event still exists and is active
    const event = await db('events')
      .where({ 
        id: decoded.eventId, 
        is_active: true, 
        is_archived: false 
      })
      .first();
    
    if (!event) {
      return res.status(404).json({ error: 'Gallery not found or expired' });
    }
    
    // Check if gallery has expired
    if (new Date(event.expires_at) < new Date()) {
      return res.status(410).json({ 
        error: 'Gallery has expired',
        code: 'GALLERY_EXPIRED'
      });
    }
    
    // Add event info to request
    req.event = event;
    req.galleryToken = decoded;
    
    next();
  } catch (error) {
    logger.error('Gallery auth middleware error:', error);
    res.status(401).json({ error: 'Authentication failed' });
  }
}

/**
 * Photo access authentication
 * Validates both admin and gallery tokens for photo access
 */
async function photoAuth(req, res, next) {
  try {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) {
      return res.status(401).json({ error: 'Authentication required' });
    }
    
    let decoded;
    try {
      decoded = jwt.verify(token, process.env.JWT_SECRET);
    } catch (err) {
      return res.status(401).json({ error: 'Invalid token' });
    }
    
    // Allow both admin and gallery tokens
    if (decoded.type === 'admin') {
      const admin = await db('admin_users')
        .where({ id: decoded.id, is_active: formatBoolean(true) })
        .first();
      
      if (!admin) {
        return res.status(401).json({ error: 'Invalid token' });
      }
      
      req.auth = { type: 'admin', user: admin };
    } else if (decoded.type === 'gallery') {
      const event = await db('events')
        .where({ 
          id: decoded.eventId, 
          is_active: true, 
          is_archived: false 
        })
        .first();
      
      if (!event) {
        return res.status(404).json({ error: 'Gallery not found' });
      }
      
      // For gallery tokens, ensure they can only access their event's photos
      req.auth = { type: 'gallery', event: event };
    } else {
      return res.status(403).json({ error: 'Invalid token type' });
    }
    
    next();
  } catch (error) {
    logger.error('Photo auth middleware error:', error);
    res.status(401).json({ error: 'Authentication failed' });
  }
}

/**
 * Verify gallery access for specific operations
 */
async function verifyGalleryAccess(req, res, next) {
  try {
    if (!req.auth) {
      return res.status(401).json({ error: 'Authentication required' });
    }
    
    const { eventId } = req.params;
    
    // Admins can access any gallery
    if (req.auth.type === 'admin') {
      return next();
    }
    
    // Gallery tokens can only access their own event
    if (req.auth.type === 'gallery') {
      if (req.auth.event.id !== parseInt(eventId)) {
        return res.status(403).json({ error: 'Access denied' });
      }
      return next();
    }
    
    res.status(403).json({ error: 'Access denied' });
  } catch (error) {
    res.status(500).json({ error: 'Access verification failed' });
  }
}

module.exports = { 
  adminAuth, 
  galleryAuth,
  photoAuth,
  verifyGalleryAccess
};