const axios = require('axios');
const logger = require('../utils/logger');

class ClaudeService {
  constructor() {
    this.apiKey = process.env.CLAUDE_API_KEY;
    this.model = process.env.CLAUDE_MODEL || 'claude-3-5-sonnet-20241022';
    this.maxTokens = parseInt(process.env.CLAUDE_MAX_TOKENS) || 4000;
    this.timeout = parseInt(process.env.REQUEST_TIMEOUT) || 30000;
    
    if (!this.apiKey) {
      logger.warn('Claude API key not configured. Claude integration will be disabled.');
    }
  }

  /**
   * Generate unified recommendation using Claude AI
   * @param {Object} techStackRecommendation - Recommendation from tech-stack-selector
   * @param {Object} templateRecommendation - Recommendation from template-manager
   * @param {Object} requestParams - Original request parameters
   * @returns {Promise<Object>} Unified recommendation
   */
  async generateUnifiedRecommendation(techStackRecommendation, templateRecommendation, requestParams) {
    if (!this.apiKey) {
      throw new Error('Claude API key not configured');
    }

    try {
      logger.info({
        message: 'Generating unified recommendation using Claude AI',
        techStackSource: techStackRecommendation.source,
        templateSource: templateRecommendation.source
      });

      const prompt = this.buildPrompt(techStackRecommendation, templateRecommendation, requestParams);
      
      const response = await axios.post(
        'https://api.anthropic.com/v1/messages',
        {
          model: this.model,
          max_tokens: this.maxTokens,
          messages: [
            {
              role: 'user',
              content: prompt
            }
          ]
        },
        {
          timeout: this.timeout,
          headers: {
            'Content-Type': 'application/json',
            'x-api-key': this.apiKey,
            'anthropic-version': '2023-06-01',
            'User-Agent': 'Unison-Service/1.0'
          }
        }
      );

      const claudeResponse = response.data.content[0].text;
      
      // Parse Claude's response
      const unifiedRecommendation = this.parseClaudeResponse(claudeResponse);
      
      logger.info({
        message: 'Successfully generated unified recommendation using Claude AI',
        stackName: unifiedRecommendation.stack_name,
        recommendationScore: unifiedRecommendation.recommendation_score
      });

      return {
        success: true,
        data: unifiedRecommendation,
        source: 'claude-ai',
        claudeModel: this.model
      };

    } catch (error) {
      logger.error({
        message: 'Failed to generate unified recommendation using Claude AI',
        error: error.message,
        techStackSource: techStackRecommendation.source,
        templateSource: templateRecommendation.source
      });

      throw new Error(`Claude AI service error: ${error.message}`);
    }
  }

  /**
   * Build the prompt for Claude AI
   * @param {Object} techStackRecommendation - Recommendation from tech-stack-selector
   * @param {Object} templateRecommendation - Recommendation from template-manager
   * @param {Object} requestParams - Original request parameters
   * @returns {string} Formatted prompt
   */
  buildPrompt(techStackRecommendation, templateRecommendation, requestParams) {
    return `You are an expert tech stack architect. I need you to analyze two different tech stack recommendations and create a single, optimized recommendation that balances cost, domain requirements, and template-feature compatibility.

## Original Request Parameters:
- Domain: ${requestParams.domain || 'Not specified'}
- Budget: $${requestParams.budget || 'Not specified'}
- Preferred Technologies: ${requestParams.preferredTechnologies ? requestParams.preferredTechnologies.join(', ') : 'Not specified'}
- Template ID: ${requestParams.templateId || 'Not specified'}

## Tech Stack Selector Recommendation:
${JSON.stringify(techStackRecommendation.data, null, 2)}

## Template Manager Recommendation:
${JSON.stringify(templateRecommendation.data, null, 2)}

## Your Task:
Analyze both recommendations and create a single, optimized tech stack recommendation that:
1. Balances cost-effectiveness with the budget constraint
2. Matches the domain requirements
3. Incorporates the best features from the template recommendation
4. Considers the preferred technologies when possible
5. Provides realistic team size, development time, and success metrics

## Required Output Format:
You MUST respond with ONLY a valid JSON object that matches this EXACT schema. Do NOT include any other text or formatting:

{
  "stack_name": "string (descriptive name for the tech stack)",
  "monthly_cost": number (monthly operational cost in USD),
  "setup_cost": number (one-time setup cost in USD),
  "team_size": "string (e.g., '1-2', '3-5', '6-10')",
  "development_time": number (weeks to complete, 1-52),
  "satisfaction": number (0-100, user satisfaction score),
  "success_rate": number (0-100, project success rate),
  "frontend": "string (specific frontend technology like 'React.js', 'Vue.js', 'Angular')",
  "backend": "string (specific backend technology like 'Node.js', 'Django', 'Spring Boot')",
  "database": "string (specific database like 'PostgreSQL', 'MongoDB', 'MySQL')",
  "cloud": "string (specific cloud platform like 'AWS', 'DigitalOcean', 'Azure')",
  "testing": "string (specific testing framework like 'Jest', 'pytest', 'Cypress')",
  "mobile": "string (mobile technology like 'React Native', 'Flutter', 'Ionic' or 'None')",
  "devops": "string (devops tool like 'Docker', 'GitHub Actions', 'Jenkins')",
  "ai_ml": "string (AI/ML technology like 'TensorFlow', 'scikit-learn', 'PyTorch' or 'None')",
  "recommended_tool": "string (primary recommended tool like 'Stripe', 'Firebase', 'Vercel')",
  "recommendation_score": number (0-100, overall recommendation score),
  "message": "string (brief explanation of the recommendation, max 500 characters)"
}

## Important Notes:
- The JSON must be valid and complete
- All numeric values should be realistic
- The recommendation should be practical and implementable
- Consider the budget constraints carefully
- Balance between cost and quality
- Include reasoning in the message field

Respond with ONLY the JSON object, no additional text or formatting.`;
  }

  /**
   * Parse Claude's response and validate it
   * @param {string} claudeResponse - Raw response from Claude
   * @returns {Object} Parsed and validated recommendation
   */
  parseClaudeResponse(claudeResponse) {
    try {
      // Extract JSON from the response (in case there's extra text)
      const jsonMatch = claudeResponse.match(/\{[\s\S]*\}/);
      if (!jsonMatch) {
        throw new Error('No JSON found in Claude response');
      }

      const parsedResponse = JSON.parse(jsonMatch[0]);
      
      // Validate required fields
      const requiredFields = [
        'stack_name', 'monthly_cost', 'setup_cost', 'team_size', 'development_time',
        'satisfaction', 'success_rate', 'frontend', 'backend', 'database', 'cloud',
        'testing', 'mobile', 'devops', 'ai_ml', 'recommended_tool', 'recommendation_score', 'message'
      ];

      const missingFields = requiredFields.filter(field => !(field in parsedResponse));
      if (missingFields.length > 0) {
        throw new Error(`Missing required fields: ${missingFields.join(', ')}`);
      }

      // Validate numeric ranges
      const numericValidations = {
        monthly_cost: { min: 0, max: 10000 },
        setup_cost: { min: 0, max: 50000 },
        development_time: { min: 1, max: 52 },
        satisfaction: { min: 0, max: 100 },
        success_rate: { min: 0, max: 100 },
        recommendation_score: { min: 0, max: 100 }
      };

      for (const [field, range] of Object.entries(numericValidations)) {
        const value = parsedResponse[field];
        if (typeof value !== 'number' || value < range.min || value > range.max) {
          throw new Error(`Invalid ${field}: ${value}. Must be a number between ${range.min} and ${range.max}`);
        }
      }

      // Validate string fields
      const stringFields = ['stack_name', 'team_size', 'frontend', 'backend', 'database', 'cloud', 'testing', 'mobile', 'devops', 'ai_ml', 'recommended_tool', 'message'];
      for (const field of stringFields) {
        if (typeof parsedResponse[field] !== 'string' || parsedResponse[field].trim().length === 0) {
          throw new Error(`Invalid ${field}: must be a non-empty string`);
        }
      }

      logger.info({
        message: 'Successfully parsed and validated Claude response',
        stackName: parsedResponse.stack_name,
        recommendationScore: parsedResponse.recommendation_score
      });

      return parsedResponse;

    } catch (error) {
      logger.error({
        message: 'Failed to parse Claude response',
        error: error.message,
        claudeResponse: claudeResponse.substring(0, 500) + '...'
      });

      throw new Error(`Failed to parse Claude response: ${error.message}`);
    }
  }

  /**
   * Check if Claude service is available
   * @returns {boolean} Service availability
   */
  isAvailable() {
    return !!this.apiKey;
  }

  /**
   * Get service configuration
   * @returns {Object} Service configuration
   */
  getConfig() {
    return {
      available: this.isAvailable(),
      model: this.model,
      maxTokens: this.maxTokens,
      timeout: this.timeout
    };
  }
}

module.exports = new ClaudeService();
