import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { ConfigService } from '@nestjs/config';
import { CandidateFeedback } from './entities/candidate_feedback.entity';
import Groq from 'groq-sdk';

@Injectable()
export class CandidateFeedbackService {
  private readonly logger = new Logger(CandidateFeedbackService.name);
  private groq: Groq;

  constructor(
    @InjectRepository(CandidateFeedback)
    private feedbackRepository: Repository<CandidateFeedback>,
    private configService: ConfigService,
  ) {
    this.groq = new Groq({
      apiKey: this.configService.get<string>('GROQ_API_KEY'),
    });
  }

  async generateAiFeedback(
    feedbackId: number,
    feedbackData: any,
    overallScore: number,
  ) {
    try {
      this.logger.log(`Generating AI feedback for feedback ID: ${feedbackId}`);

      const systemPrompt = `You are an expert frontend technical interviewer and hiring evaluator.
Your task is to generate clear, professional, and unbiased feedback
based strictly on provided skill performance data from a mock assessment.
Rules:
- Do NOT mention specific questions, answers, MCQs, or options
- Do NOT change or recalculate scores
- Do NOT invent new skills or results
- Explain performance at a conceptual level
- Keep feedback concise, recruiter-friendly, and constructive
Output format must be JSON with exactly these keys:
- strength_summary
- focus_areas
- improvement_plan
Guidelines:
- Strength summary: string, explain why these areas are strong
- Focus areas: string, explain conceptual gaps causing low performance
- Improvement plan: array of strings, each string being an actionable step
Tone: professional, neutral, improvement-oriented`;

      const topicPerformanceStr = Object.entries(
        feedbackData.topic_performance || {},
      )
        .map(
          ([topic, data]: [string, any]) => `- ${topic}: ${data.percentage}%`,
        )
        .join('\n');

      const userPrompt = `Mock Test Performance Data:
Overall Score: ${Math.round(overallScore)}%
Strong Areas:
${(feedbackData.strengths || []).join(', ')}
Improvement Areas:
${(feedbackData.improvement_areas || []).join(', ')}
Topic-wise Performance (percentage accuracy):
${topicPerformanceStr}
Generate structured feedback as instructed.`;

      const completion = await this.groq.chat.completions.create({
        messages: [
          {
            role: 'system',
            content: systemPrompt,
          },
          {
            role: 'user',
            content: userPrompt,
          },
        ],
        model: 'llama-3.1-8b-instant',
        temperature: 0.3,
        max_tokens: 1024,
        top_p: 1,
        stream: false,
        stop: null,
        response_format: { type: 'json_object' },
      });

      const aiResponse = completion.choices[0]?.message?.content;
      if (!aiResponse) {
        this.logger.warn('Empty response from Groq');
        return;
      }

      let parsedFeedback;
      try {
        parsedFeedback = JSON.parse(aiResponse);
      } catch (e) {
        this.logger.error('Failed to parse AI response as JSON', e);
        return;
      }

      const sanitize = (val: any): string => {
        if (typeof val === 'string') return val;
        if (Array.isArray(val)) {
          // Handle array of objects
          if (val.length > 0 && typeof val[0] === 'object' && val[0] !== null) {
            return val
              .map((item) => {
                // Try common keys or just join values
                const text =
                  item.text ||
                  item.step ||
                  item.action ||
                  item.description ||
                  item.value ||
                  Object.values(item)
                    .filter((v) => typeof v === 'string')
                    .join(': ');
                return text || JSON.stringify(item);
              })
              .join('\n');
          }
          return val.join('\n');
        }
        if (typeof val === 'object' && val !== null) return JSON.stringify(val);
        return String(val || '');
      };

      const sanitizedFeedback = {
        strength_summary: sanitize(parsedFeedback.strength_summary),
        focus_areas: sanitize(parsedFeedback.focus_areas),
        improvement_plan: sanitize(parsedFeedback.improvement_plan),
        llm_generated: 1,
        llm_provider: 'groq',
      };

      if (!feedbackId) {
        throw new Error('Cannot update feedback: feedbackId is missing');
      }
      // console.log(`[Feedback] Updating feedback ID: ${feedbackId}`);

      await this.feedbackRepository.update(feedbackId, sanitizedFeedback);

      this.logger.log(`AI feedback saved for feedback ID: ${feedbackId}`);
      return sanitizedFeedback;
    } catch (error) {
      this.logger.error(
        `Error generating AI feedback: ${error.message}`,
        error.stack,
      );
      // We do not throw here to avoid failing the main request if AI fails
      return null;
    }
  }

  async inferTopicsForQuestions(
    questions: { id: number; question: string }[],
  ): Promise<Map<number, string[]>> {
    if (questions.length === 0) return new Map();

    try {
      const prompt = `Analyze the following interview questions and assign 1-2 relevant technical topic tags to each.
      Input Questions:
      ${questions.map((q) => `ID ${q.id}: ${q.question}`).join('\n')}

      Output must be valid JSON object where keys are Question IDs and values are arrays of topic strings.
      Example: { "123": ["React", "Hooks"], "124": ["JavaScript", "Async"] }
      Only return JSON.`;

      const completion = await this.groq.chat.completions.create({
        messages: [{ role: 'user', content: prompt }],
        model: 'llama-3.1-8b-instant',
        temperature: 0.1,
        response_format: { type: 'json_object' },
      });

      const response = completion.choices[0]?.message?.content;
      if (!response) return new Map();

      const parsed = JSON.parse(response);
      const resultMap = new Map<number, string[]>();

      Object.entries(parsed).forEach(([key, value]) => {
        if (Array.isArray(value)) {
          resultMap.set(Number(key), value as string[]);
        }
      });

      return resultMap;
    } catch (error) {
      this.logger.error('Failed to infer topics', error);
      return new Map();
    }
  }
}
