import logger, { logAIEvent } from '@utils/logger';
import { getConfigValue } from './configReader.service';
import { VertexAI } from '@google-cloud/vertexai';
import { resolve } from 'path';

// Vertex AI Configuration
const PROJECT_ID = process.env.GCP_PROJECT_ID || 're-platform-workflow-dealer';
const LOCATION = process.env.VERTEX_AI_LOCATION || 'asia-south1';
const KEY_FILE_PATH = process.env.GCP_KEY_FILE || resolve(__dirname, '../../credentials/re-platform-workflow-dealer-3d5738fcc1f9.json');
const DEFAULT_MODEL = 'gemini-2.5-flash';

class AIService {
  private vertexAI: VertexAI | null = null;
  private model: string = DEFAULT_MODEL;
  private isInitialized: boolean = false;
  private providerName: string = 'Vertex AI (Gemini)';

  constructor() {
    // Initialization happens asynchronously
    this.initialize();
  }

  /**
   * Initialize Vertex AI client
   */
  async initialize(): Promise<void> {
    try {
      // Check if AI is enabled from config
      const { getConfigBoolean } = require('./configReader.service');
      const enabled = await getConfigBoolean('AI_ENABLED', true);

      if (!enabled) {
        logger.warn('[AI Service] AI features disabled in admin configuration');
        this.isInitialized = true;
        return;
      }

      // Get model and location from environment variables only
      this.model = process.env.VERTEX_AI_MODEL || DEFAULT_MODEL;
      const location = process.env.VERTEX_AI_LOCATION || LOCATION;

      logger.info(`[AI Service] Initializing Vertex AI with project: ${PROJECT_ID}, location: ${location}, model: ${this.model}`);

      // Initialize Vertex AI client with service account credentials
      this.vertexAI = new VertexAI({
        project: PROJECT_ID,
        location: location,
        googleAuthOptions: {
          keyFilename: KEY_FILE_PATH,
        },
      });

      logger.info(`[AI Service] ✅ Vertex AI provider initialized successfully with model: ${this.model}`);
      this.isInitialized = true;
    } catch (error: any) {
      logger.error('[AI Service] Failed to initialize Vertex AI:', error);

      if (error.code === 'MODULE_NOT_FOUND') {
        logger.warn('[AI Service] @google-cloud/vertexai package not installed. Run: npm install @google-cloud/vertexai');
      } else if (error.message?.includes('ENOENT') || error.message?.includes('not found')) {
        logger.error(`[AI Service] Service account key file not found at: ${KEY_FILE_PATH}`);
        logger.error('[AI Service] Please ensure the credentials file exists and GCP_KEY_FILE path is correct');
      } else if (error.message?.includes('Could not load the default credentials')) {
        logger.error('[AI Service] Failed to load service account credentials. Please verify the key file is valid.');
      } else {
        logger.error(`[AI Service] Initialization error: ${error.message}`);
      }

      this.isInitialized = true; // Mark as initialized even if failed to prevent infinite loops
    }
  }

  /**
   * Reinitialize AI provider (call after admin updates config)
   */
  async reinitialize(): Promise<void> {
    logger.info('[AI Service] Reinitializing Vertex AI provider from updated configuration...');
    this.vertexAI = null;
    this.isInitialized = false;
    await this.initialize();
  }

  /**
   * Get current AI provider name
   */
  getProviderName(): string {
    return this.providerName;
  }

  /**
   * Generate text using Vertex AI Gemini
   */
  private async generateText(prompt: string): Promise<string> {
    if (!this.vertexAI) {
      throw new Error('Vertex AI client not initialized');
    }

    logAIEvent('request', { provider: 'vertex-ai', model: this.model });

    try {
      // Get the generative model
      // Increase maxOutputTokens to handle longer conclusions (up to ~4000 tokens ≈ 3000 words)
      const generativeModel = this.vertexAI.getGenerativeModel({
        model: this.model,
        generationConfig: {
          maxOutputTokens: 4096, // Increased from 2048 to handle longer conclusions
          temperature: 0.3,
        },
      });

      // Generate content
      const request = {
        contents: [{ role: 'user', parts: [{ text: prompt }] }],
      };

      const streamingResp = await generativeModel.generateContent(request);
      const response = streamingResp.response;

      // Log full response structure for debugging if empty
      if (!response.candidates || response.candidates.length === 0) {
        logger.error('[AI Service] No candidates in Vertex AI response:', {
          response: JSON.stringify(response, null, 2),
          promptLength: prompt.length,
          model: this.model
        });
        throw new Error('Vertex AI returned no candidates. The response may have been blocked by safety filters.');
      }

      const candidate = response.candidates[0];

      // Check for safety ratings or blocked reasons
      if (candidate.safetyRatings && candidate.safetyRatings.length > 0) {
        const blockedRatings = candidate.safetyRatings.filter((rating: any) =>
          rating.probability === 'HIGH' || rating.probability === 'MEDIUM'
        );
        if (blockedRatings.length > 0) {
          logger.warn('[AI Service] Vertex AI safety filters triggered:', {
            ratings: blockedRatings.map((r: any) => ({
              category: r.category,
              probability: r.probability
            })),
            finishReason: candidate.finishReason
          });
        }
      }

      // Check finish reason
      if (candidate.finishReason && candidate.finishReason !== 'STOP') {
        logger.warn('[AI Service] Vertex AI finish reason:', {
          finishReason: candidate.finishReason,
          safetyRatings: candidate.safetyRatings
        });
      }

      // Extract text from response
      const text = candidate.content?.parts?.[0]?.text || '';

      // Handle MAX_TOKENS finish reason - accept whatever response we got
      // We trust the AI's response - no truncation on our side
      if (candidate.finishReason === 'MAX_TOKENS' && text) {
        // Accept the response as-is - AI was instructed to stay within limits
        // If it hit the limit, we still use what we got (no truncation on our side)
        logger.info('[AI Service] Vertex AI response hit token limit, but content received is preserved as-is:', {
          textLength: text.length,
          finishReason: candidate.finishReason
        });
        // Return the response without any truncation - trust what AI generated
        return text;
      }

      if (!text) {
        // Log detailed response structure for debugging
        logger.error('[AI Service] Empty text in Vertex AI response:', {
          candidate: JSON.stringify(candidate, null, 2),
          finishReason: candidate.finishReason,
          safetyRatings: candidate.safetyRatings,
          promptLength: prompt.length,
          promptPreview: prompt.substring(0, 200) + '...',
          model: this.model
        });

        // Provide more helpful error message
        if (candidate.finishReason === 'SAFETY') {
          throw new Error('Vertex AI blocked the response due to safety filters. The prompt may contain content that violates safety policies.');
        } else if (candidate.finishReason === 'MAX_TOKENS') {
          throw new Error('Vertex AI response was truncated due to token limit. The prompt may be too long or the response limit was exceeded.');
        } else if (candidate.finishReason === 'RECITATION') {
          throw new Error('Vertex AI blocked the response due to recitation concerns.');
        } else {
          throw new Error(`Empty response from Vertex AI. Finish reason: ${candidate.finishReason || 'UNKNOWN'}`);
        }
      }

      return text;
    } catch (error: any) {
      logger.error('[AI Service] Vertex AI generation error:', error);

      // Provide more specific error messages
      if (error.message?.includes('Model was not found')) {
        throw new Error(`Model ${this.model} not found or not available in region ${LOCATION}. Please check model name and region.`);
      } else if (error.message?.includes('Permission denied')) {
        throw new Error('Permission denied. Please verify service account has Vertex AI User role.');
      } else if (error.message?.includes('API not enabled')) {
        throw new Error('Vertex AI API is not enabled. Please enable it in Google Cloud Console.');
      }

      throw new Error(`Vertex AI generation failed: ${error.message}`);
    }
  }

  /**
   * Generate conclusion remark for a workflow request
   * @param context - All relevant data for generating the conclusion
   * @returns AI-generated conclusion remark
   */
  async generateConclusionRemark(context: {
    requestTitle: string;
    requestDescription: string;
    requestNumber: string;
    priority: string;
    approvalFlow: Array<{
      levelNumber: number;
      approverName: string;
      status: string;
      comments?: string;
      actionDate?: string;
      tatHours?: number;
      elapsedHours?: number;
    }>;
    workNotes: Array<{
      userName: string;
      message: string;
      createdAt: string;
    }>;
    documents: Array<{
      fileName: string;
      uploadedBy: string;
      uploadedAt: string;
    }>;
    activities: Array<{
      type: string;
      action: string;
      details: string;
      timestamp: string;
    }>;
  }): Promise<{ remark: string; confidence: number; keyPoints: string[]; provider: string }> {
    // Ensure initialization is complete
    if (!this.isInitialized) {
      logger.warn('[AI Service] Not yet initialized, attempting initialization...');
      await this.initialize();
    }

    if (!this.vertexAI) {
      logger.error('[AI Service] Vertex AI not available');
      throw new Error('AI features are currently unavailable. Please verify Vertex AI configuration and service account credentials.');
    }

    try {
      // Build context prompt with max length from config
      const prompt = await this.buildConclusionPrompt(context);

      logger.info(`[AI Service] Generating conclusion for request ${context.requestNumber} using ${this.providerName} (${this.model})...`);

      // Use Vertex AI to generate text
      let remarkText = await this.generateText(prompt);

      // Get max length from config for logging
      const maxLengthStr = await getConfigValue('AI_MAX_REMARK_LENGTH', '2000');
      const maxLength = parseInt(maxLengthStr || '2000', 10);

      // Trust AI's response - do not truncate anything
      // AI is instructed to stay within limit, but we accept whatever it generates
      // Trust AI's response - do not truncate anything
      // AI is instructed to stay within limit, but we accept whatever it generates
      if (remarkText.length > maxLength) {
        logger.info(`[AI Service] AI generated ${remarkText.length} characters (suggested limit: ${maxLength}). Full content preserved as-is.`);
        logger.info(`[AI Service] AI generated ${remarkText.length} characters (suggested limit: ${maxLength}). Full content preserved as-is.`);
      }

      // Extract key points (look for bullet points or numbered items)
      const keyPoints = this.extractKeyPoints(remarkText);

      // Calculate confidence based on response quality (simple heuristic)
      const confidence = this.calculateConfidence(remarkText, context);

      logger.info(`[AI Service] ✅ Generated conclusion (${remarkText.length}/${maxLength} chars, ${keyPoints.length} key points) via ${this.providerName}`);

      return {
        remark: remarkText,
        confidence: confidence,
        keyPoints: keyPoints,
        provider: this.providerName
      };
    } catch (error: any) {
      logger.error('[AI Service] Failed to generate conclusion:', error);
      throw new Error(`AI generation failed (${this.providerName}): ${error.message}`);
    }
  }

  /**
   * Build the prompt for Vertex AI to generate a professional conclusion remark
   */
  private async buildConclusionPrompt(context: any): Promise<string> {
    const {
      requestTitle,
      requestDescription,
      requestNumber,
      priority,
      approvalFlow,
      workNotes,
      documents,
      activities,
      rejectionReason,
      rejectedBy
    } = context;

    // Get max remark length from admin configuration
    const maxLengthStr = await getConfigValue('AI_MAX_REMARK_LENGTH', '2000');
    const maxLength = parseInt(maxLengthStr || '2000', 10);
    const targetWordCount = Math.floor(maxLength / 6); // Approximate words (avg 6 chars per word)

    logger.info(`[AI Service] Using max remark length: ${maxLength} characters (≈${targetWordCount} words) from admin config`);

    // Check if this is a rejected request
    const isRejected = rejectionReason || rejectedBy || approvalFlow.some((a: any) => a.status === 'REJECTED');

    // Helper function to determine TAT risk status
    const getTATRiskStatus = (tatPercentage: number): string => {
      if (tatPercentage < 50) return 'ON_TRACK';
      if (tatPercentage < 75) return 'AT_RISK';
      if (tatPercentage < 100) return 'CRITICAL';
      return 'BREACHED';
    };

    // Summarize approvals with TAT risk information
    const approvalSummary = approvalFlow
      .filter((a: any) => a.status === 'APPROVED' || a.status === 'REJECTED')
      .map((a: any) => {
        const tatPercentage = a.tatPercentageUsed !== undefined && a.tatPercentageUsed !== null
          ? Number(a.tatPercentageUsed)
          : (a.elapsedHours && a.tatHours ? (Number(a.elapsedHours) / Number(a.tatHours)) * 100 : 0);
        const riskStatus = getTATRiskStatus(tatPercentage);
        const tatInfo = a.elapsedHours && a.tatHours
          ? ` (completed in ${a.elapsedHours.toFixed(1)}h of ${a.tatHours}h TAT, ${tatPercentage.toFixed(1)}% used)`
          : '';
        const riskInfo = riskStatus !== 'ON_TRACK' ? ` [${riskStatus}]` : '';
        return `- Level ${a.levelNumber}: ${a.approverName} ${a.status}${tatInfo}${riskInfo}${a.comments ? `\n  Comment: "${a.comments}"` : ''}`;
      })
      .join('\n');

    // Summarize work notes (limit to important ones)
    const workNoteSummary = workNotes
      .slice(-10) // Last 10 work notes
      .map((wn: any) => `- ${wn.userName}: "${wn.message.substring(0, 150)}${wn.message.length > 150 ? '...' : ''}"`)
      .join('\n');

    // Summarize documents (limit to reduce token usage)
    const documentSummary = documents
      .slice(0, 10) // Limit to first 10 documents
      .map((d: any) => `- ${d.fileName} (by ${d.uploadedBy})`)
      .join('\n');

    // Build rejection context if applicable
    const rejectionContext = isRejected
      ? `\n**Rejection Details:**\n- Rejected by: ${rejectedBy || 'Approver'}\n- Rejection reason: ${rejectionReason || 'Not specified'}`
      : '';

    const prompt = `You are writing a closure summary for a workflow request at Royal Enfield. Write a practical, realistic conclusion that an employee would write when closing a request.

**Request:**
${requestNumber} - ${requestTitle}
Description: ${requestDescription}
Priority: ${priority}

**What Happened:**
${approvalSummary || 'No approvals recorded'}${rejectionContext}

**Discussions (if any):**
${workNoteSummary || 'No work notes'}

**Documents:**
${documentSummary || 'No documents'}

**YOUR TASK:**
Write a brief, professional conclusion (approximately ${targetWordCount} words, max ${maxLength} characters) that:
${isRejected
        ? `- Summarizes what was requested and explains that it was rejected
- Mentions who rejected it and the rejection reason
- Notes the outcome and any learnings or next steps
- Mentions if any approval levels were AT_RISK, CRITICAL, or BREACHED (if applicable)
- Uses clear, factual language without time-specific references
- Is suitable for permanent archiving and future reference
- Sounds natural and human-written (not AI-generated)
- Maintains a professional and constructive tone even for rejections`
        : `- Summarizes what was requested and the final decision
- Mentions who approved it and any key comments
- Mentions if any approval levels were AT_RISK, CRITICAL, or BREACHED (if applicable)
- Notes the outcome and next steps (if applicable)
- Uses clear, factual language without time-specific references
- Is suitable for permanent archiving and future reference
- Sounds natural and human-written (not AI-generated)`}

**CRITICAL CHARACTER LIMIT - STRICT REQUIREMENT:**
- Your response MUST stay within ${maxLength} characters (not words, CHARACTERS including spaces including HTML tags)
- This is a HARD LIMIT - you must count your characters and ensure your complete response fits within ${maxLength} characters
- Count your characters carefully before responding - include all HTML tags in your count
- If you have too much content, PRIORITIZE the most important information:
  1. Final decision (approved/rejected)
  2. Key approvers and their decisions
  3. Critical TAT breaches (if any)
  4. Brief summary of the request
- OMIT less important details to fit within the limit rather than exceeding it
- Better to be concise and complete within the limit than to exceed it
- IMPORTANT: Generate your complete response within this limit - do not generate partial content that exceeds the limit

**WRITING GUIDELINES:**
- Be concise and direct - every word must add value
- No time-specific words like "today", "now", "currently", "recently"
- No corporate jargon or buzzwords
- No emojis
- Write like a professional documenting a completed process
- Focus on facts: what was requested, who ${isRejected ? 'rejected' : 'approved'}, what was decided
- Use past tense for completed actions
- Use short sentences and avoid filler words

**FORMAT REQUIREMENT - HTML Rich Text:**
- Generate content in HTML format for rich text editor display
- Use proper HTML tags for structure and formatting:
  * <p>...</p> for paragraphs
  * <strong>...</strong> for important text/headings
  * <ul><li>...</li></ul> for bullet points
  * <ol><li>...</li></ol> for numbered lists
  * <br> for line breaks only when necessary
- Use semantic HTML to make the content readable and well-structured
- Example format:
  <p><strong>Request Summary:</strong> [Brief description]</p>
  <p><strong>Approval Decision:</strong> [Decision details]</p>
  <ul>
    <li>Key point 1</li>
    <li>Key point 2</li>
  </ul>
  <p><strong>Outcome:</strong> [Final outcome]</p>
- Keep HTML clean and minimal - no inline styles, no divs, no classes
- The HTML should render nicely in a rich text editor

Write the conclusion now in HTML format. STRICT LIMIT: ${maxLength} characters maximum (including HTML tags). Prioritize and condense if needed:`;

    return prompt;
  }

  /**
   * Extract key points from the AI-generated remark
   */
  private extractKeyPoints(remark: string): string[] {
    const keyPoints: string[] = [];

    // Look for bullet points (-, •, *) or numbered items (1., 2., etc.)
    const lines = remark.split('\n');

    for (const line of lines) {
      const trimmed = line.trim();

      // Match bullet points
      if (trimmed.match(/^[-•*]\s+(.+)$/)) {
        const point = trimmed.replace(/^[-•*]\s+/, '');
        if (point.length > 10) { // Ignore very short lines
          keyPoints.push(point);
        }
      }

      // Match numbered items
      if (trimmed.match(/^\d+\.\s+(.+)$/)) {
        const point = trimmed.replace(/^\d+\.\s+/, '');
        if (point.length > 10) {
          keyPoints.push(point);
        }
      }
    }

    // If no bullet points found, extract first few sentences
    if (keyPoints.length === 0) {
      const sentences = remark.split(/[.!?]+/).filter(s => s.trim().length > 20);
      keyPoints.push(...sentences.slice(0, 3).map(s => s.trim()));
    }

    return keyPoints.slice(0, 5); // Max 5 key points
  }

  /**
   * Calculate confidence score based on response quality
   */
  private calculateConfidence(remark: string, context: any): number {
    let score = 0.6; // Base score

    // Check if remark has good length (100-400 chars - more realistic)
    if (remark.length >= 100 && remark.length <= 400) {
      score += 0.2;
    }

    // Check if remark mentions key elements
    if (remark.toLowerCase().includes('approv')) {
      score += 0.1;
    }

    // Check if remark is not too generic
    if (remark.length > 80 && !remark.toLowerCase().includes('lorem ipsum')) {
      score += 0.1;
    }

    return Math.min(1.0, score);
  }

  /**
   * Check if AI service is available
   */
  isAvailable(): boolean {
    return this.vertexAI !== null;
  }
}

export const aiService = new AIService();
