/**
 * API Key Authentication Middleware
 * Validates API keys and attaches user info to request
 */

const crypto = require('crypto');
const { query } = require('../database/connection');
const { cacheGet, cacheSet } = require('../cache/redis');

/**
 * Authenticate requests using X-API-Key header
 */
async function authenticateApiKey(req, res, next) {
    try {
        const apiKey = req.headers['x-api-key'];

        // Check if API key is provided
        if (!apiKey) {
            return res.status(401).json({
                success: false,
                error: { code: 'MISSING_API_KEY', message: 'API key required' }
            });
        }

        // Validate API key format using env prefix
        const expectedPrefix = process.env.API_KEY_PREFIX || 'vi_';
        if (!apiKey.startsWith(expectedPrefix)) {
            return res.status(401).json({
                success: false,
                error: { code: 'INVALID_API_KEY_FORMAT', message: 'Invalid API key format' }
            });
        }

        // Try to get from Redis cache first
        const cacheKey = `apikey:${apiKey}`;
        let keyData = await cacheGet(cacheKey);

        if (!keyData) {
            // Cache miss - query database
            const keyHash = crypto.createHash('sha256').update(apiKey).digest('hex');

            const result = await query(
                `SELECT ak.*, u.plan, u.monthly_quota, u.calls_this_month, u.is_active as user_active
         FROM api_keys ak
         JOIN users u ON ak.user_id = u.id
         WHERE ak.key_hash = $1 AND ak.is_active = true`,
                [keyHash]
            );

            if (result.rows.length === 0) {
                return res.status(401).json({
                    success: false,
                    error: { code: 'INVALID_API_KEY', message: 'Invalid or inactive API key' }
                });
            }

            keyData = result.rows[0];

            // Cache for 5 minutes
            await cacheSet(cacheKey, keyData, 300);
        }

        // Check if user account is active
        if (!keyData.user_active) {
            return res.status(403).json({
                success: false,
                error: { code: 'ACCOUNT_INACTIVE', message: 'Account inactive' }
            });
        }

        // Check quota
        if (keyData.calls_this_month >= keyData.monthly_quota) {
            return res.status(429).json({
                success: false,
                error: {
                    code: 'QUOTA_EXCEEDED',
                    message: 'Monthly quota exceeded',
                    details: { used: keyData.calls_this_month, limit: keyData.monthly_quota }
                }
            });
        }

        // Attach user info to request
        req.user = {
            id: keyData.user_id,
            plan: keyData.plan,
            apiKeyId: keyData.id,
            isTestKey: keyData.is_test_key,
            quota: keyData.monthly_quota,
            used: keyData.calls_this_month,
            remaining: keyData.monthly_quota - keyData.calls_this_month
        };

        next();
    } catch (error) {
        console.error('Auth error:', error);
        return res.status(500).json({
            success: false,
            error: { code: 'AUTH_ERROR', message: 'Authentication failed' }
        });
    }
}

/**
 * Authenticate requests using JWT Bearer token
 */
const jwt = require('jsonwebtoken');

async function authenticateJWT(req, res, next) {
    try {
        const authHeader = req.headers['authorization'];

        if (!authHeader || !authHeader.startsWith('Bearer ')) {
            return res.status(401).json({
                success: false,
                error: { code: 'MISSING_TOKEN', message: 'Bearer token required' }
            });
        }

        const token = authHeader.split(' ')[1];

        const decoded = jwt.verify(token, process.env.JWT_SECRET);

        // Get user from database
        const result = await query(
            'SELECT id, email, company_name, plan, monthly_quota, calls_this_month FROM users WHERE id = $1 AND is_active = true',
            [decoded.userId]
        );

        if (result.rows.length === 0) {
            return res.status(401).json({
                success: false,
                error: { code: 'USER_NOT_FOUND', message: 'User not found or inactive' }
            });
        }

        req.user = result.rows[0];
        next();
    } catch (error) {
        if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
            return res.status(401).json({
                success: false,
                error: { code: 'INVALID_TOKEN', message: 'Invalid or expired token' }
            });
        }

        return res.status(500).json({
            success: false,
            error: { code: 'AUTH_ERROR', message: 'Authentication failed' }
        });
    }
}

module.exports = { authenticateApiKey, authenticateJWT };
