const express = require('express');
const techStackService = require('../services/techStackService');
const templateService = require('../services/templateService');
const claudeService = require('../services/claudeService');
const DatabaseService = require('../services/databaseService');
const schemaValidator = require('../utils/schemaValidator');
const logger = require('../utils/logger');
const { v4: uuidv4 } = require('uuid');

// Create database service instance
const databaseService = new DatabaseService();

const router = express.Router();

/**
 * POST /api/recommendations/unified
 * Get unified tech stack recommendation combining both services
 */
router.post('/unified', async (req, res) => {
  try {
    const startTime = Date.now();
    
    // Extract request parameters with defaults
    const {
      domain = 'general',
      budget = 5000,
      preferredTechnologies = [],
      templateId,
      includeSimilar = false,
      includeKeywords = false,
      forceRefresh = false
    } = req.body;

    logger.info({
      message: 'Processing unified recommendation request',
      domain,
      budget,
      preferredTechnologies,
      templateId,
      includeSimilar,
      includeKeywords,
      forceRefresh
    });


    // Use default values if not provided
    const techStackRequest = { domain, budget, preferredTechnologies };
    const techStackValidation = schemaValidator.validateTechStackRequest(techStackRequest);
    if (!techStackValidation.valid) {
      return res.status(400).json({
        success: false,
        error: 'Invalid tech stack request parameters',
        details: techStackValidation.errors
      });
    }

    // If templateId is provided, validate it
    if (templateId) {
      const templateRequest = { templateId, includeSimilar, includeKeywords, forceRefresh };
      const templateValidation = schemaValidator.validateTemplateRequest(templateRequest);
      if (!templateValidation.valid) {
        return res.status(400).json({
          success: false,
          error: 'Invalid template request parameters',
          details: templateValidation.errors
        });
      }
    }

    // Fetch recommendations from services
    const promises = [];

    // Always fetch from tech-stack-selector (domain + budget based)
    promises.push(
      techStackService.getRecommendations({
        domain,
        budget,
        preferredTechnologies
      }).catch(error => {
        logger.error({
          message: 'Failed to fetch from tech-stack-selector',
          error: error.message
        });
        return { success: false, error: error.message, source: 'tech-stack-selector' };
      })
    );

    // Fetch from template-manager if templateId is provided
    if (templateId) {
      promises.push(
        templateService.getAIRecommendations(templateId, { forceRefresh })
          .catch(error => {
            logger.error({
              message: 'Failed to fetch from template-manager',
              error: error.message,
              templateId
            });
            return { success: false, error: error.message, source: 'template-manager' };
          })
      );
    } else {
      // If no templateId, provide a default template recommendation
      promises.push(Promise.resolve({ 
        success: true, 
        data: {
          stack_name: 'Default General Purpose Stack',
          monthly_cost: 100,
          setup_cost: 2000,
          team_size: '2-3',
          development_time: 4,
          satisfaction: 85,
          success_rate: 80,
          frontend: 'React',
          backend: 'Node.js',
          database: 'PostgreSQL',
          cloud: 'AWS',
          testing: 'Jest',
          mobile: 'React Native',
          devops: 'Docker',
          ai_ml: 'Not specified',
          recommendation_score: 85.0
        },
        source: 'template-manager-default' 
      }));
    }

    const [techStackResult, templateResult] = await Promise.all(promises);

    // Check if we have at least one successful recommendation
    if (!techStackResult.success && !templateResult.success) {
      return res.status(500).json({
        success: false,
        error: 'Failed to fetch recommendations from both services',
        details: {
          techStackError: techStackResult.error,
          templateError: templateResult.error
        }
      });
    }

    // Both services must succeed for unified recommendations
    if (!techStackResult.success || !templateResult.success) {
      return res.status(500).json({
        success: false,
        error: 'Both services are required for unified recommendations',
        message: 'Both tech-stack-selector and template-manager must be available for unified recommendations',
        processingTime: Date.now() - startTime,
        services: {
          techStackSelector: techStackResult.success ? 'available' : 'unavailable',
          templateManager: templateResult.success ? 'available' : 'unavailable'
        }
      });
    }

    // Both services returned recommendations - use Claude to unify them
    if (!claudeService.isAvailable()) {
      return res.status(500).json({
        success: false,
        error: 'Claude AI service is required for unified recommendations',
        message: 'Claude AI is not available. Unified recommendations require Claude AI to process both tech-stack and template recommendations.',
        processingTime: Date.now() - startTime,
        services: {
          techStackSelector: 'available',
          templateManager: 'available',
          claudeAI: 'unavailable'
        }
      });
    }

    // Generate unified recommendation using Claude
    const claudeResult = await claudeService.generateUnifiedRecommendation(
      techStackResult,
      templateResult,
      { domain, budget, preferredTechnologies, templateId }
    );

    // Log Claude AI response for debugging
    logger.info({
      message: 'Claude AI response received',
      claudeResponse: claudeResult.data,
      claudeModel: claudeResult.claudeModel
    });

    // Validate the unified recommendation
    const validation = schemaValidator.validateUnifiedRecommendation(claudeResult.data);
    if (!validation.valid) {
      logger.warn({
        message: 'Claude generated invalid recommendation, using tech-stack-selector as fallback',
        validationErrors: validation.errors,
        claudeResponse: claudeResult.data
      });

      return res.json({
        success: true,
        data: techStackResult.data,
        source: 'tech-stack-selector (fallback)',
        message: 'Claude generated invalid recommendation, using tech-stack-selector as fallback',
        processingTime: Date.now() - startTime,
        services: {
          techStackSelector: 'available',
          templateManager: 'available',
          claudeAI: 'invalid_output'
        }
      });
    }

    logger.info({
      message: 'Successfully generated unified recommendation',
      stackName: claudeResult.data.stack_name,
      recommendationScore: claudeResult.data.recommendation_score,
      processingTime: Date.now() - startTime
    });

    // Store recommendation in database
    const requestId = uuidv4();
    const processingTime = Date.now() - startTime;
    
    // Use a default template ID if none provided (represents "no template" case)
    const templateIdForStorage = templateId || '00000000-0000-0000-0000-000000000000';
    
    try {
      const storageResult = await databaseService.storeRecommendation({
        requestId,
        domain,
        budget,
        preferredTechnologies,
        templateId: templateIdForStorage,
        stackName: claudeResult.data.stack_name,
        monthlyCost: claudeResult.data.monthly_cost,
        setupCost: claudeResult.data.setup_cost,
        teamSize: claudeResult.data.team_size,
        developmentTime: claudeResult.data.development_time,
        satisfaction: claudeResult.data.satisfaction,
        successRate: claudeResult.data.success_rate,
        frontend: claudeResult.data.frontend,
        backend: claudeResult.data.backend,
        database: claudeResult.data.database,
        cloud: claudeResult.data.cloud,
        testing: claudeResult.data.testing,
        mobile: claudeResult.data.mobile,
        devops: claudeResult.data.devops,
        aiMl: claudeResult.data.ai_ml,
        recommendedTool: claudeResult.data.recommended_tool,
        recommendationScore: claudeResult.data.recommendation_score,
        message: claudeResult.data.message,
        claudeModel: claudeResult.claudeModel,
        processingTime
      });

      if (storageResult.success) {
        logger.info(`Recommendation stored in database with ID: ${storageResult.id}`);
      } else {
        logger.warn(`Failed to store recommendation in database: ${storageResult.error}`);
      }
    } catch (storageError) {
      logger.error('Error storing recommendation in database:', storageError);
      // Don't fail the request if storage fails
    }

    res.json({
      success: true,
      data: claudeResult.data,
      source: 'unified',
      message: 'Unified recommendation generated successfully',
      processingTime,
      services: {
        techStackSelector: 'available',
        templateManager: 'available',
        claudeAI: 'available'
      },
      claudeModel: claudeResult.claudeModel,
      requestId, // Include request ID for tracking
      templateId: templateId || null // Show original templateId (null if not provided)
    });

  } catch (error) {
    logger.error({
      message: 'Error processing unified recommendation request',
      error: error.message,
      stack: error.stack,
      body: req.body
    });

    res.status(500).json({
      success: false,
      error: 'Internal server error',
      message: error.message
    });
  }
});

/**
 * GET /api/recommendations/tech-stack
 * Get recommendations from tech-stack-selector only
 */
router.get('/tech-stack', async (req, res) => {
  try {
    const { domain, budget, preferredTechnologies } = req.query;

    // Convert string parameters to appropriate types
    const params = {
      domain: domain || undefined,
      budget: budget ? parseFloat(budget) : undefined,
      preferredTechnologies: preferredTechnologies ? preferredTechnologies.split(',') : undefined
    };

    // Remove undefined values
    Object.keys(params).forEach(key => {
      if (params[key] === undefined) {
        delete params[key];
      }
    });

    const result = await techStackService.getRecommendations(params);
    
    res.json({
      success: true,
      data: result.data,
      source: 'tech-stack-selector',
      message: 'Tech stack recommendations retrieved successfully'
    });

  } catch (error) {
    logger.error({
      message: 'Error fetching tech stack recommendations',
      error: error.message,
      query: req.query
    });

    res.status(500).json({
      success: false,
      error: 'Failed to fetch tech stack recommendations',
      message: error.message
    });
  }
});

/**
 * GET /api/recommendations/template/:templateId
 * Get recommendations from template-manager only
 */
router.get('/template/:templateId', async (req, res) => {
  try {
    const { templateId } = req.params;
    const { force_refresh } = req.query;

    // Validate UUID format
    const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
    if (!uuidRegex.test(templateId)) {
      return res.status(400).json({
        success: false,
        error: 'Invalid template ID format',
        message: 'Template ID must be a valid UUID format',
        providedId: templateId
      });
    }

    const result = await templateService.getAIRecommendations(templateId, {
      forceRefresh: force_refresh === 'true'
    });
    
    res.json({
      success: true,
      data: result.data,
      source: 'template-manager',
      message: 'Template recommendations retrieved successfully'
    });

  } catch (error) {
    logger.error({
      message: 'Error fetching template recommendations',
      error: error.message,
      templateId: req.params.templateId
    });

    res.status(500).json({
      success: false,
      error: 'Failed to fetch template recommendations',
      message: error.message
    });
  }
});

/**
 * GET /api/recommendations/endpoints
 * Get available API endpoints
 */
router.get('/endpoints', (req, res) => {
  res.json({
    success: true,
    data: {
      endpoints: [
        {
          method: 'POST',
          path: '/api/recommendations/unified',
          description: 'Get unified tech stack recommendation combining both services',
          parameters: {
            domain: 'string (optional, default: "general")',
            budget: 'number (optional, default: 5000)',
            preferredTechnologies: 'array (optional, default: [])',
            templateId: 'string (optional, UUID format)',
            includeSimilar: 'boolean (optional, default: false)',
            includeKeywords: 'boolean (optional, default: false)',
            forceRefresh: 'boolean (optional, default: false)'
          }
        },
        {
          method: 'GET',
          path: '/api/recommendations/tech-stack',
          description: 'Get recommendations from tech-stack-selector only',
          parameters: {
            domain: 'string (required)',
            budget: 'number (required)',
            preferredTechnologies: 'array (optional)'
          }
        },
        {
          method: 'GET',
          path: '/api/recommendations/template/:templateId',
          description: 'Get recommendations from template-manager only',
          parameters: {
            templateId: 'string (required, UUID format)',
            force_refresh: 'boolean (optional, query parameter)'
          }
        },
        {
          method: 'GET',
          path: '/api/recommendations/stored',
          description: 'Get stored recommendations from database',
          parameters: {
            limit: 'number (optional, default: 10)',
            domain: 'string (optional, filter by domain)',
            templateId: 'string (optional, filter by template ID)'
          }
        },
        {
          method: 'GET',
          path: '/api/recommendations/stored/:id',
          description: 'Get specific stored recommendation by ID',
          parameters: {
            id: 'string (required, UUID format)'
          }
        },
        {
          method: 'GET',
          path: '/api/recommendations/stats',
          description: 'Get recommendation statistics',
          parameters: 'none'
        },
        {
          method: 'GET',
          path: '/api/recommendations/schemas',
          description: 'Get available validation schemas',
          parameters: 'none'
        }
      ]
    },
    message: 'Available API endpoints'
  });
});

/**
 * GET /api/recommendations/schemas
 * Get available validation schemas
 */
router.get('/schemas', (req, res) => {
  try {
    const schemas = schemaValidator.getAvailableSchemas();
    const schemaDefinitions = {};

    schemas.forEach(schemaName => {
      schemaDefinitions[schemaName] = schemaValidator.getSchema(schemaName);
    });

    res.json({
      success: true,
      data: {
        availableSchemas: schemas,
        schemas: schemaDefinitions
      },
      message: 'Available schemas retrieved successfully'
    });

  } catch (error) {
    logger.error({
      message: 'Error fetching schemas',
      error: error.message
    });

    res.status(500).json({
      success: false,
      error: 'Failed to fetch schemas',
      message: error.message
    });
  }
});

/**
 * GET /api/recommendations/stored
 * Get stored recommendations with optional filtering
 */
router.get('/stored', async (req, res) => {
  try {
    const { domain, templateId, limit = 20 } = req.query;
    
    let recommendations;
    if (domain) {
      recommendations = await databaseService.getRecommendationsByDomain(domain, parseInt(limit));
    } else if (templateId) {
      recommendations = await databaseService.getRecommendationsByTemplateId(templateId, parseInt(limit));
    } else {
      recommendations = await databaseService.getRecentRecommendations(parseInt(limit));
    }

    res.json({
      success: true,
      data: recommendations,
      count: recommendations.length,
      filters: { domain, templateId, limit: parseInt(limit) }
    });

  } catch (error) {
    logger.error({
      message: 'Error fetching stored recommendations',
      error: error.message,
      query: req.query
    });

    res.status(500).json({
      success: false,
      error: 'Failed to fetch stored recommendations',
      message: error.message
    });
  }
});

/**
 * GET /api/recommendations/stored/:id
 * Get a specific stored recommendation by ID
 */
router.get('/stored/:id', async (req, res) => {
  try {
    const { id } = req.params;
    const recommendation = await databaseService.getRecommendationById(id);

    if (!recommendation) {
      return res.status(404).json({
        success: false,
        error: 'Recommendation not found',
        message: `No recommendation found with ID: ${id}`
      });
    }

    res.json({
      success: true,
      data: recommendation
    });

  } catch (error) {
    logger.error({
      message: 'Error fetching recommendation by ID',
      error: error.message,
      id: req.params.id
    });

    res.status(500).json({
      success: false,
      error: 'Failed to fetch recommendation',
      message: error.message
    });
  }
});

/**
 * GET /api/recommendations/stats
 * Get statistics about stored recommendations
 */
router.get('/stats', async (req, res) => {
  try {
    const stats = await databaseService.getRecommendationStats();

    res.json({
      success: true,
      data: stats
    });

  } catch (error) {
    logger.error({
      message: 'Error fetching recommendation stats',
      error: error.message
    });

    res.status(500).json({
      success: false,
      error: 'Failed to fetch recommendation statistics',
      message: error.message
    });
  }
});

module.exports = router;
