import { Request, Response } from 'express';
import { WorkflowRequest, ApprovalLevel, WorkNote, Document, Activity, ConclusionRemark } from '@models/index';
import { isHtmlEmpty } from '../utils/sanitizer';
import { aiService } from '@services/ai.service';
import { activityService } from '@services/activity.service';
import logger from '@utils/logger';
import { getRequestMetadata } from '@utils/requestUtils';


export class ConclusionController {
  /**
   * Generate AI conclusion remark for a request
   * POST /api/v1/conclusions/:requestId/generate
   */
  async generateConclusion(req: Request, res: Response) {
    try {
      const { requestId } = req.params;
      const userId = (req as any).user?.userId;

      // Fetch request with all related data
      const request = await WorkflowRequest.findOne({
        where: { requestId },
        include: [
          { association: 'initiator', attributes: ['userId', 'displayName', 'email'] }
        ]
      });

      if (!request) {
        return res.status(404).json({ error: 'Request not found' });
      }

      // Check if user is the initiator
      if ((request as any).initiatorId !== userId) {
        return res.status(403).json({ error: 'Only the initiator can generate conclusion remarks' });
      }

      // Check if request is approved or rejected
      if ((request as any).status !== 'APPROVED' && (request as any).status !== 'REJECTED') {
        return res.status(400).json({ error: 'Conclusion can only be generated for approved or rejected requests' });
      }

      // Check if AI features are enabled in admin config
      const { getConfigValue } = await import('../services/configReader.service');
      const aiEnabled = (await getConfigValue('AI_ENABLED', 'true'))?.toLowerCase() === 'true';
      const remarkGenerationEnabled = (await getConfigValue('AI_REMARK_GENERATION_ENABLED', 'true'))?.toLowerCase() === 'true';

      if (!aiEnabled) {
        logger.warn(`[Conclusion] AI features disabled in admin config for request ${requestId}`);
        return res.status(400).json({
          error: 'AI features disabled',
          message: 'AI features are currently disabled by administrator. Please write the conclusion manually.',
          canContinueManually: true
        });
      }

      if (!remarkGenerationEnabled) {
        logger.warn(`[Conclusion] AI remark generation disabled in admin config for request ${requestId}`);
        return res.status(400).json({
          error: 'AI remark generation disabled',
          message: 'AI-powered conclusion generation is currently disabled by administrator. Please write the conclusion manually.',
          canContinueManually: true
        });
      }

      // Check if AI service is available
      if (!aiService.isAvailable()) {
        logger.warn(`[Conclusion] AI service unavailable for request ${requestId}`);
        return res.status(503).json({
          error: 'AI service not available',
          message: 'AI features are currently unavailable. Please verify Vertex AI configuration and service account credentials, or write the conclusion manually.',
          canContinueManually: true
        });
      }

      // Gather context for AI generation
      const approvalLevels = await ApprovalLevel.findAll({
        where: { requestId },
        order: [['levelNumber', 'ASC']]
      });

      const workNotes = await WorkNote.findAll({
        where: { requestId },
        order: [['createdAt', 'ASC']],
        limit: 20 // Last 20 work notes - keep full context for better conclusions
      });

      const documents = await Document.findAll({
        where: { requestId },
        order: [['uploadedAt', 'DESC']]
      });

      const activities = await Activity.findAll({
        where: { requestId },
        order: [['createdAt', 'ASC']],
        limit: 50 // Last 50 activities - keep full context for better conclusions
      });

      // Build context object
      const context = {
        requestTitle: (request as any).title,
        requestDescription: (request as any).description,
        requestNumber: (request as any).requestNumber,
        priority: (request as any).priority,
        approvalFlow: approvalLevels.map((level: any) => {
          const tatPercentage = level.tatPercentageUsed !== undefined && level.tatPercentageUsed !== null
            ? Number(level.tatPercentageUsed)
            : (level.elapsedHours && level.tatHours ? (Number(level.elapsedHours) / Number(level.tatHours)) * 100 : 0);
          return {
            levelNumber: level.levelNumber,
            approverName: level.approverName,
            status: level.status,
            comments: level.comments,
            actionDate: level.actionDate,
            tatHours: Number(level.tatHours || 0),
            elapsedHours: Number(level.elapsedHours || 0),
            tatPercentageUsed: tatPercentage
          };
        }),
        workNotes: workNotes.map((note: any) => ({
          userName: note.userName,
          message: note.message,
          createdAt: note.createdAt
        })),
        documents: documents.map((doc: any) => ({
          fileName: doc.originalFileName || doc.fileName,
          uploadedBy: doc.uploadedBy,
          uploadedAt: doc.uploadedAt
        })),
        activities: activities.map((activity: any) => ({
          type: activity.activityType,
          action: activity.activityDescription,
          details: activity.activityDescription,
          timestamp: activity.createdAt
        }))
      };

      logger.info(`[Conclusion] Generating AI remark for request ${requestId}...`);

      // Generate AI conclusion
      const aiResult = await aiService.generateConclusionRemark(context);

      // Check if conclusion already exists
      let conclusionInstance = await ConclusionRemark.findOne({ where: { requestId } });

      const conclusionData = {
        aiGeneratedRemark: aiResult.remark,
        aiModelUsed: aiResult.provider,
        aiConfidenceScore: aiResult.confidence,
        approvalSummary: {
          totalLevels: approvalLevels.length,
          approvedLevels: approvalLevels.filter((l: any) => l.status === 'APPROVED').length,
          averageTatUsage: approvalLevels.reduce((sum: number, l: any) =>
            sum + Number(l.tatPercentageUsed || 0), 0) / (approvalLevels.length || 1)
        },
        documentSummary: {
          totalDocuments: documents.length,
          documentNames: documents.map((d: any) => d.originalFileName || d.fileName)
        },
        keyDiscussionPoints: aiResult.keyPoints,
        generatedAt: new Date()
      };

      if (conclusionInstance) {
        // Update existing conclusion (allow regeneration)
        await conclusionInstance.update(conclusionData as any);
        logger.info(`[Conclusion] ✅ AI conclusion regenerated for request ${requestId}`);
      } else {
        // Create new conclusion
        conclusionInstance = await ConclusionRemark.create({
          requestId,
          ...conclusionData,
          finalRemark: null,
          editedBy: null,
          isEdited: false,
          editCount: 0,
          finalizedAt: null
        } as any);
        logger.info(`[Conclusion] ✅ AI conclusion generated for request ${requestId}`);
      }

      // Log activity
      const requestMeta = getRequestMetadata(req);
      await activityService.log({
        requestId,
        type: 'ai_conclusion_generated',
        user: { userId, name: (request as any).initiator?.displayName || 'Initiator' },
        timestamp: new Date().toISOString(),
        action: 'AI Conclusion Generated',
        details: 'AI-powered conclusion remark generated for review',
        ipAddress: requestMeta.ipAddress,
        userAgent: requestMeta.userAgent
      });

      return res.status(200).json({
        message: 'Conclusion generated successfully',
        data: {
          conclusionId: (conclusionInstance as any).conclusionId,
          aiGeneratedRemark: aiResult.remark,
          keyDiscussionPoints: aiResult.keyPoints,
          confidence: aiResult.confidence,
          provider: aiResult.provider,
          generatedAt: new Date()
        }
      });
    } catch (error: any) {
      logger.error('[Conclusion] Error generating conclusion:', error);

      // Provide helpful error messages
      const isConfigError = error.message?.includes('not configured') ||
        error.message?.includes('not available') ||
        error.message?.includes('not initialized');

      return res.status(isConfigError ? 503 : 500).json({
        error: isConfigError ? 'AI service not configured' : 'Failed to generate conclusion',
        message: error.message || 'An unexpected error occurred',
        canContinueManually: true // User can still write manual conclusion
      });
    }
  }

  /**
   * Update conclusion remark (edit by initiator)
   * PUT /api/v1/conclusions/:requestId
   */
  async updateConclusion(req: Request, res: Response) {
    try {
      const { requestId } = req.params;
      const { finalRemark } = req.body;
      const userId = (req as any).user?.userId;

      if (isHtmlEmpty(finalRemark)) {
        return res.status(400).json({ error: 'A valid final remark is required. Please ensure the remark contains valid content.' });
      }

      // Fetch request
      const request = await WorkflowRequest.findOne({ where: { requestId } });
      if (!request) {
        return res.status(404).json({ error: 'Request not found' });
      }

      // Check if user is the initiator
      if ((request as any).initiatorId !== userId) {
        return res.status(403).json({ error: 'Only the initiator can update conclusion remarks' });
      }

      // Find conclusion
      const conclusion = await ConclusionRemark.findOne({ where: { requestId } });
      if (!conclusion) {
        return res.status(404).json({ error: 'Conclusion not found. Generate it first.' });
      }

      // Update conclusion
      // Note: finalRemark is already sanitized by the sanitization middleware (RICH_TEXT_FIELDS)
      const wasEdited = (conclusion as any).aiGeneratedRemark !== finalRemark;

      await conclusion.update({
        finalRemark: finalRemark,
        editedBy: userId,
        isEdited: wasEdited,
        editCount: wasEdited ? (conclusion as any).editCount + 1 : (conclusion as any).editCount
      } as any);

      logger.info(`[Conclusion] Updated conclusion for request ${requestId} (edited: ${wasEdited})`);

      return res.status(200).json({
        message: 'Conclusion updated successfully',
        data: conclusion
      });
    } catch (error: any) {
      logger.error('[Conclusion] Error updating conclusion:', error);
      return res.status(500).json({ error: 'Failed to update conclusion' });
    }
  }

  /**
   * Finalize conclusion and close request
   * POST /api/v1/conclusions/:requestId/finalize
   */
  async finalizeConclusion(req: Request, res: Response) {
    try {
      const { requestId } = req.params;
      const { finalRemark } = req.body;
      const userId = (req as any).user?.userId;

      if (!finalRemark || typeof finalRemark !== 'string') {
        return res.status(400).json({ error: 'Final remark is required' });
      }

      // Note: finalRemark is already sanitized by the sanitization middleware (RICH_TEXT_FIELDS)

      // Fetch request
      const request = await WorkflowRequest.findOne({
        where: { requestId },
        include: [
          { association: 'initiator', attributes: ['userId', 'displayName', 'email'] }
        ]
      });

      if (!request) {
        return res.status(404).json({ error: 'Request not found' });
      }

      // Check if user is the initiator
      if ((request as any).initiatorId !== userId) {
        return res.status(403).json({ error: 'Only the initiator can finalize conclusion remarks' });
      }

      // Check if request is approved or rejected
      if ((request as any).status !== 'APPROVED' && (request as any).status !== 'REJECTED') {
        return res.status(400).json({ error: 'Only approved or rejected requests can be closed' });
      }

      // Find or create conclusion
      let conclusion = await ConclusionRemark.findOne({ where: { requestId } });

      if (!conclusion) {
        // Create if doesn't exist (manual conclusion without AI)
        conclusion = await ConclusionRemark.create({
          requestId,
          aiGeneratedRemark: null,
          aiModelUsed: null,
          aiConfidenceScore: null,
          finalRemark: finalRemark,
          editedBy: userId,
          isEdited: false,
          editCount: 0,
          approvalSummary: {},
          documentSummary: {},
          keyDiscussionPoints: [],
          generatedAt: null,
          finalizedAt: new Date()
        } as any);
      } else {
        // Update existing conclusion
        const wasEdited = (conclusion as any).aiGeneratedRemark !== finalRemark;

        await conclusion.update({
          finalRemark: finalRemark,
          editedBy: userId,
          isEdited: wasEdited,
          editCount: wasEdited ? (conclusion as any).editCount + 1 : (conclusion as any).editCount,
          finalizedAt: new Date()
        } as any);
      }

      // Update request status to CLOSED
      await request.update({
        status: 'CLOSED',
        conclusionRemark: finalRemark,
        closureDate: new Date()
      } as any);

      logger.info(`[Conclusion] ✅ Request ${requestId} finalized and closed`);

      // Automatically create summary when request is closed (idempotent - returns existing if already exists)
      // Since the initiator is finalizing, this should always succeed
      let summaryId = null;
      try {
        const { summaryService } = await import('@services/summary.service');
        const userRole = (req as any).user?.role || (req as any).auth?.role;
        const summary = await summaryService.createSummary(requestId, userId, { userRole });
        summaryId = (summary as any).summaryId;
        logger.info(`[Conclusion] ✅ Summary ${summaryId} created automatically for closed request ${requestId}`);
      } catch (summaryError: any) {
        // Log error but don't fail the closure if summary creation fails
        // Frontend can retry summary creation if needed
        logger.error(`[Conclusion] Failed to create summary for request ${requestId}:`, summaryError.message);
      }

      // Log activity
      const requestMeta = getRequestMetadata(req);
      await activityService.log({
        requestId,
        type: 'closed',
        user: { userId, name: (request as any).initiator?.displayName || 'Initiator' },
        timestamp: new Date().toISOString(),
        action: 'Request Closed',
        details: `Request closed with conclusion remark by ${(request as any).initiator?.displayName}`,
        ipAddress: requestMeta.ipAddress,
        userAgent: requestMeta.userAgent
      });

      return res.status(200).json({
        message: 'Request finalized and closed successfully',
        data: {
          conclusionId: (conclusion as any).conclusionId,
          requestNumber: (request as any).requestNumber,
          status: 'CLOSED',
          finalRemark: finalRemark,
          finalizedAt: (conclusion as any).finalizedAt,
          summaryId: summaryId // Include summaryId in response
        }
      });
    } catch (error: any) {
      logger.error('[Conclusion] Error finalizing conclusion:', error);
      return res.status(500).json({ error: 'Failed to finalize conclusion' });
    }
  }

  /**
   * Get conclusion for a request
   * GET /api/v1/conclusions/:requestId
   */
  async getConclusion(req: Request, res: Response) {
    try {
      const { requestId } = req.params;

      const conclusion = await ConclusionRemark.findOne({
        where: { requestId },
        include: [
          { association: 'editor', attributes: ['userId', 'displayName', 'email'] }
        ]
      });

      if (!conclusion) {
        return res.status(404).json({ error: 'Conclusion not found' });
      }

      return res.status(200).json({
        message: 'Conclusion retrieved successfully',
        data: conclusion
      });
    } catch (error: any) {
      logger.error('[Conclusion] Error getting conclusion:', error);
      return res.status(500).json({ error: 'Failed to get conclusion' });
    }
  }
}

export const conclusionController = new ConclusionController();

