import { RequestSummary, SharedSummary, WorkflowRequest, ApprovalLevel, User, ConclusionRemark, Participant } from '@models/index';
import '@models/index'; // Ensure associations are loaded
import { Op } from 'sequelize';
import logger from '@utils/logger';
import dayjs from 'dayjs';

export class SummaryService {
  /**
   * Create a summary for a closed request
   * Pulls data from workflow_requests, approval_levels, and conclusion_remarks
   * 
   * Access Control:
   * - 'system': Allows system-level auto-generation on final approval
   * - initiator: The request initiator can create/regenerate
   * - admin/management: Admin or management role users can create/regenerate via API
   * 
   * @param requestId - The workflow request ID
   * @param userId - The user ID requesting the summary (or 'system' for auto-generation)
   * @param options - Optional parameters
   * @param options.isSystemGeneration - Set to true for system-level auto-generation
   * @param options.userRole - The role of the user (for admin access check)
   * @param options.regenerate - Set to true to regenerate (delete existing and create new)
   */
  async createSummary(
    requestId: string, 
    userId: string,
    options?: { isSystemGeneration?: boolean; userRole?: string; regenerate?: boolean }
  ): Promise<RequestSummary> {
    try {
      const { isSystemGeneration = false, userRole, regenerate = false } = options || {};
      
      // Check if request exists and is closed
      const workflow = await WorkflowRequest.findByPk(requestId, {
        include: [
          { association: 'initiator', attributes: ['userId', 'email', 'displayName', 'designation', 'department'] }
        ]
      });

      if (!workflow) {
        throw new Error('Workflow request not found');
      }

      // Verify request is closed (APPROVED, REJECTED, or CLOSED)
      const status = (workflow as any).status?.toUpperCase();
      if (status !== 'APPROVED' && status !== 'REJECTED' && status !== 'CLOSED') {
        throw new Error('Request must be closed (APPROVED, REJECTED, or CLOSED) before creating summary');
      }

      const initiatorId = (workflow as any).initiatorId;
      const isInitiator = initiatorId === userId;
      const isAdmin = userRole && ['admin', 'super_admin', 'management'].includes(userRole.toLowerCase());
      
      // Access control: Allow system generation, initiator, or admin users
      if (!isSystemGeneration && !isInitiator && !isAdmin) {
        throw new Error('Only the initiator or admin users can create a summary for this request');
      }

      // Check if summary already exists
      const existingSummary = await RequestSummary.findOne({
        where: { requestId }
      });

      if (existingSummary) {
        // If regenerate is requested by initiator or admin, delete existing and create new
        if (regenerate && (isInitiator || isAdmin)) {
          logger.info(`[Summary] Regenerating summary for request ${requestId}`);
          await existingSummary.destroy();
        } else {
          // Return existing summary (idempotent behavior)
          logger.info(`Summary already exists for request ${requestId}, returning existing summary`);
          return existingSummary as RequestSummary;
        }
      }

      // Get conclusion remarks
      const conclusion = await ConclusionRemark.findOne({
        where: { requestId }
      });

      // Get all approval levels ordered by level number
      const approvalLevels = await ApprovalLevel.findAll({
        where: { requestId },
        order: [['levelNumber', 'ASC']],
        include: [
          {
            model: User,
            as: 'approver',
            attributes: ['userId', 'email', 'displayName', 'designation', 'department']
          }
        ]
      });

      // Determine closing remarks
      let closingRemarks: string | null = null;
      let isAiGenerated = false;
      let conclusionId: string | null = null;

      if (conclusion) {
        conclusionId = (conclusion as any).conclusionId;
        // Use final remark if edited, otherwise use AI-generated
        closingRemarks = (conclusion as any).finalRemark || (conclusion as any).aiGeneratedRemark || null;
        isAiGenerated = !(conclusion as any).isEdited && !!(conclusion as any).aiGeneratedRemark;
      } else {
        // Fallback to workflow's conclusion remark if no conclusion_remarks record
        closingRemarks = (workflow as any).conclusionRemark || null;
        isAiGenerated = false;
      }

      // Create summary - always use the actual initiator from the workflow
      const summary = await RequestSummary.create({
        requestId,
        initiatorId: initiatorId, // Use workflow's initiator, not the requesting user
        title: (workflow as any).title || '',
        description: (workflow as any).description || null,
        closingRemarks,
        isAiGenerated,
        conclusionId
      });

      const generationType = isSystemGeneration ? 'system' : (isAdmin ? 'admin' : 'initiator');
      logger.info(`[Summary] Created summary ${(summary as any).summaryId} for request ${requestId} (generated by: ${generationType})`);
      return summary;
    } catch (error) {
      logger.error(`[Summary] Failed to create summary for request ${requestId}:`, error);
      throw error;
    }
  }

  /**
   * Get summary details by sharedSummaryId (for recipients)
   */
  async getSummaryDetailsBySharedId(sharedSummaryId: string, userId: string): Promise<any> {
    try {
      const shared = await SharedSummary.findByPk(sharedSummaryId, {
        include: [
          {
            model: RequestSummary,
            as: 'summary',
            include: [
              {
                model: WorkflowRequest,
                as: 'request',
                include: [
                  {
                    model: User,
                    as: 'initiator',
                    attributes: ['userId', 'email', 'displayName', 'designation', 'department']
                  }
                ]
              },
              {
                model: User,
                as: 'initiator',
                attributes: ['userId', 'email', 'displayName', 'designation', 'department']
              },
              {
                model: ConclusionRemark,
                attributes: ['conclusionId', 'aiGeneratedRemark', 'finalRemark', 'isEdited', 'generatedAt', 'finalizedAt']
              }
            ]
          }
        ]
      });

      if (!shared) {
        throw new Error('Shared summary not found');
      }

      // Verify access
      if ((shared as any).sharedWith !== userId) {
        throw new Error('Access denied: You do not have permission to view this summary');
      }

      const summary = (shared as any).summary;
      if (!summary) {
        throw new Error('Associated summary not found');
      }

      const request = (summary as any).request;
      if (!request) {
        throw new Error('Associated workflow request not found');
      }

      // Mark as viewed
      await shared.update({
        viewedAt: new Date(),
        isRead: true
      });

      // Get all approval levels with approver details
      const approvalLevels = await ApprovalLevel.findAll({
        where: { requestId: (request as any).requestId },
        order: [['levelNumber', 'ASC']],
        include: [
          {
            model: User,
            as: 'approver',
            attributes: ['userId', 'email', 'displayName', 'designation', 'department']
          }
        ]
      });

      // Format approver data for summary
      const approvers = approvalLevels.map((level: any) => {
        const approver = (level as any).approver || {};
        const status = (level.status || '').toString().toUpperCase();
        
        // Determine remarks based on status
        let remarks: string | null = null;
        if (status === 'APPROVED') {
          remarks = level.comments || null;
        } else if (status === 'REJECTED') {
          remarks = level.rejectionReason || level.comments || null;
        } else if (status === 'SKIPPED') {
          remarks = (level as any).skipReason || 'Skipped' || null;
        }

        // Determine timestamp
        let timestamp: Date | null = null;
        if (level.actionDate) {
          timestamp = level.actionDate;
        } else if (level.levelStartTime) {
          timestamp = level.levelStartTime;
        } else {
          timestamp = level.createdAt;
        }

        return {
          levelNumber: level.levelNumber,
          levelName: level.levelName || `Approver ${level.levelNumber}`,
          name: approver.displayName || level.approverName || 'Unknown',
          designation: approver.designation || 'N/A',
          department: approver.department || null,
          email: approver.email || level.approverEmail || 'N/A',
          status: this.formatStatus(status),
          timestamp: timestamp,
          remarks: remarks || '—'
        };
      });

      // Format initiator data
      const initiator = (request as any).initiator || {};
      const initiatorTimestamp = (request as any).submissionDate || (request as any).createdAt;

      // Get conclusion remark if available
      let conclusionRemark = (summary as any).ConclusionRemark || (summary as any).conclusionRemark;
      
      // If not loaded and we have conclusionId, fetch by conclusionId
      if (!conclusionRemark && (summary as any).conclusionId) {
        conclusionRemark = await ConclusionRemark.findByPk((summary as any).conclusionId);
      }
      
      // If still not found, fetch by requestId (summary may have been created before conclusion)
      if (!conclusionRemark) {
        conclusionRemark = await ConclusionRemark.findOne({
          where: { requestId: (request as any).requestId }
        });
      }
      
      // Determine effective final remark:
      // - If user edited: use finalRemark
      // - If user closed without editing: use aiGeneratedRemark (becomes final)
      // - Otherwise: use closingRemarks from summary snapshot
      const effectiveFinalRemark = conclusionRemark?.finalRemark || 
                                   conclusionRemark?.aiGeneratedRemark || 
                                   (summary as any).closingRemarks || 
                                   '—';
      
      logger.info(`[Summary] SharedSummary ${sharedSummaryId}: Effective final remark length: ${effectiveFinalRemark?.length || 0} chars (isEdited: ${conclusionRemark?.isEdited}, hasAI: ${!!conclusionRemark?.aiGeneratedRemark}, hasFinal: ${!!conclusionRemark?.finalRemark})`);

      return {
        summaryId: (summary as any).summaryId,
        requestId: (request as any).requestId,
        requestNumber: (request as any).requestNumber || 'N/A',
        title: (summary as any).title || (request as any).title || '',
        description: (summary as any).description || (request as any).description || '',
        closingRemarks: effectiveFinalRemark, // ✅ Effective final remark (edited or AI)
        isAiGenerated: (summary as any).isAiGenerated || false,
        createdAt: (summary as any).createdAt,
        // Include conclusion remark data for detailed view
        conclusionRemark: conclusionRemark ? {
          aiGeneratedRemark: conclusionRemark.aiGeneratedRemark,
          finalRemark: conclusionRemark.finalRemark,
          effectiveFinalRemark: effectiveFinalRemark, // ✅ Computed field for convenience
          isEdited: conclusionRemark.isEdited,
          generatedAt: conclusionRemark.generatedAt,
          finalizedAt: conclusionRemark.finalizedAt
        } : null,
        initiator: {
          name: initiator.displayName || 'Unknown',
          designation: initiator.designation || 'N/A',
          department: initiator.department || null,
          email: initiator.email || 'N/A',
          status: 'Initiated',
          timestamp: initiatorTimestamp,
          remarks: '—'
        },
        approvers: approvers,
        workflow: {
          priority: (request as any).priority || 'STANDARD',
          status: (request as any).status || 'CLOSED',
          submissionDate: (request as any).submissionDate,
          closureDate: (request as any).closureDate,
          conclusionRemark: effectiveFinalRemark // ✅ Use effective final remark
        }
      };
    } catch (error) {
      logger.error(`[Summary] Failed to get summary details by shared ID ${sharedSummaryId}:`, error);
      throw error;
    }
  }

  /**
   * Get summary by requestId (without creating it)
   * Returns null if summary doesn't exist
   */
  async getSummaryByRequestId(requestId: string, userId: string): Promise<RequestSummary | null> {
    try {
      const summary = await RequestSummary.findOne({
        where: { requestId }
      });

      if (!summary) {
        return null;
      }

      // Check access: initiator, participants, management, or explicitly shared users
      const isInitiator = (summary as any).initiatorId === userId;
      
      // Check if user is a participant (approver or spectator)
      const isParticipant = await Participant.findOne({
        where: { requestId, userId }
      });
      
      // Check if user has management/admin role
      const currentUser = await User.findByPk(userId);
      const userRole = (currentUser as any)?.role?.toUpperCase();
      const isManagement = userRole && ['ADMIN', 'SUPER_ADMIN', 'MANAGEMENT'].includes(userRole);
      
      // Check if explicitly shared
      const isShared = await SharedSummary.findOne({
        where: {
          summaryId: (summary as any).summaryId,
          sharedWith: userId
        }
      });

      if (!isInitiator && !isParticipant && !isManagement && !isShared) {
        return null; // No access, return null instead of throwing error
      }

      return summary as RequestSummary;
    } catch (error) {
      logger.error(`[Summary] Failed to get summary by requestId ${requestId}:`, error);
      return null;
    }
  }

  /**
   * Get summary details with all approver information
   */
  async getSummaryDetails(summaryId: string, userId: string): Promise<any> {
    try {
      const summary = await RequestSummary.findByPk(summaryId, {
        include: [
          {
            model: WorkflowRequest,
            as: 'request',
            include: [
              {
                model: User,
                as: 'initiator',
                attributes: ['userId', 'email', 'displayName', 'designation', 'department']
              }
            ]
          },
          {
            model: User,
            as: 'initiator',
            attributes: ['userId', 'email', 'displayName', 'designation', 'department']
          },
          {
            model: ConclusionRemark,
            attributes: ['conclusionId', 'aiGeneratedRemark', 'finalRemark', 'isEdited', 'generatedAt', 'finalizedAt']
          }
        ]
      });

      if (!summary) {
        throw new Error('Summary not found');
      }

      const request = (summary as any).request;
      if (!request) {
        throw new Error('Associated workflow request not found');
      }

      // Check access: initiator, participants, management, or explicitly shared users
      const isInitiator = (summary as any).initiatorId === userId;
      
      // Check if user is a participant (approver or spectator) in the request
      const isParticipant = await Participant.findOne({
        where: {
          requestId: (request as any).requestId,
          userId
        }
      });
      
      // Check if user has management/admin role
      const currentUser = await User.findByPk(userId);
      const userRole = (currentUser as any)?.role?.toUpperCase();
      const isManagement = userRole && ['ADMIN', 'SUPER_ADMIN', 'MANAGEMENT'].includes(userRole);
      
      // Check if explicitly shared
      const isShared = await SharedSummary.findOne({
        where: {
          summaryId,
          sharedWith: userId
        }
      });

      if (!isInitiator && !isParticipant && !isManagement && !isShared) {
        throw new Error('Access denied: You do not have permission to view this summary');
      }

      // Get all approval levels with approver details
      const approvalLevels = await ApprovalLevel.findAll({
        where: { requestId: (request as any).requestId },
        order: [['levelNumber', 'ASC']],
        include: [
          {
            model: User,
            as: 'approver',
            attributes: ['userId', 'email', 'displayName', 'designation', 'department']
          }
        ]
      });

      // Format approver data for summary
      const approvers = approvalLevels.map((level: any) => {
        const approver = (level as any).approver || {};
        const status = (level.status || '').toString().toUpperCase();
        
        // Determine remarks based on status
        let remarks: string | null = null;
        if (status === 'APPROVED') {
          remarks = level.comments || null;
        } else if (status === 'REJECTED') {
          remarks = level.rejectionReason || level.comments || null;
        } else if (status === 'SKIPPED') {
          remarks = (level as any).skipReason || 'Skipped' || null;
        }

        // Determine timestamp
        let timestamp: Date | null = null;
        if (level.actionDate) {
          timestamp = level.actionDate;
        } else if (level.levelStartTime) {
          timestamp = level.levelStartTime;
        } else {
          timestamp = level.createdAt;
        }

        return {
          levelNumber: level.levelNumber,
          levelName: level.levelName || `Approver ${level.levelNumber}`,
          name: approver.displayName || level.approverName || 'Unknown',
          designation: approver.designation || 'N/A',
          department: approver.department || null,
          email: approver.email || level.approverEmail || 'N/A',
          status: this.formatStatus(status),
          timestamp: timestamp,
          remarks: remarks || '—'
        };
      });

      // Format initiator data
      const initiator = (request as any).initiator || {};
      const initiatorTimestamp = (request as any).submissionDate || (request as any).createdAt;

      // Get conclusion remark if available
      let conclusionRemark = (summary as any).ConclusionRemark || (summary as any).conclusionRemark;
      
      // If not loaded and we have conclusionId, fetch by conclusionId
      if (!conclusionRemark && (summary as any).conclusionId) {
        conclusionRemark = await ConclusionRemark.findByPk((summary as any).conclusionId);
      }
      
      // If still not found, fetch by requestId (summary may have been created before conclusion)
      if (!conclusionRemark) {
        conclusionRemark = await ConclusionRemark.findOne({
          where: { requestId: (request as any).requestId }
        });
      }
      
      // Determine effective final remark:
      // - If user edited: use finalRemark
      // - If user closed without editing: use aiGeneratedRemark (becomes final)
      // - Otherwise: use closingRemarks from summary snapshot
      const effectiveFinalRemark = conclusionRemark?.finalRemark || 
                                   conclusionRemark?.aiGeneratedRemark || 
                                   (summary as any).closingRemarks || 
                                   '—';
      
      logger.info(`[Summary] Summary ${summaryId}: Effective final remark length: ${effectiveFinalRemark?.length || 0} chars (isEdited: ${conclusionRemark?.isEdited}, hasAI: ${!!conclusionRemark?.aiGeneratedRemark}, hasFinal: ${!!conclusionRemark?.finalRemark})`);

      return {
        summaryId: (summary as any).summaryId,
        requestId: (request as any).requestId,
        requestNumber: (request as any).requestNumber || 'N/A',
        title: (summary as any).title || (request as any).title || '',
        description: (summary as any).description || (request as any).description || '',
        closingRemarks: effectiveFinalRemark, // ✅ Effective final remark (edited or AI)
        isAiGenerated: (summary as any).isAiGenerated || false,
        createdAt: (summary as any).createdAt,
        // Include conclusion remark data for detailed view
        conclusionRemark: conclusionRemark ? {
          aiGeneratedRemark: conclusionRemark.aiGeneratedRemark,
          finalRemark: conclusionRemark.finalRemark,
          effectiveFinalRemark: effectiveFinalRemark, // ✅ Computed field: finalRemark || aiGeneratedRemark
          isEdited: conclusionRemark.isEdited,
          generatedAt: conclusionRemark.generatedAt,
          finalizedAt: conclusionRemark.finalizedAt
        } : null,
        initiator: {
          name: initiator.displayName || 'Unknown',
          designation: initiator.designation || 'N/A',
          department: initiator.department || null,
          email: initiator.email || 'N/A',
          status: 'Initiated',
          timestamp: initiatorTimestamp,
          remarks: '—'
        },
        approvers: approvers,
        workflow: {
          priority: (request as any).priority || 'STANDARD',
          status: (request as any).status || 'CLOSED',
          submissionDate: (request as any).submissionDate,
          closureDate: (request as any).closureDate,
          conclusionRemark: effectiveFinalRemark // ✅ Use effective final remark
        }
      };
    } catch (error) {
      logger.error(`[Summary] Failed to get summary details for ${summaryId}:`, error);
      throw error;
    }
  }

  /**
   * Share summary with users
   * userIds can be either Okta IDs or internal UUIDs - we'll convert them to internal UUIDs
   */
  async shareSummary(summaryId: string, sharedBy: string, userIds: string[]): Promise<SharedSummary[]> {
    try {
      // Verify summary exists and user is the initiator
      const summary = await RequestSummary.findByPk(summaryId);
      if (!summary) {
        throw new Error('Summary not found');
      }

      if ((summary as any).initiatorId !== sharedBy) {
        throw new Error('Only the initiator can share this summary');
      }

      // Remove duplicates
      const uniqueUserIds = Array.from(new Set(userIds));

      // Convert Okta IDs to internal UUIDs
      // The frontend may send Okta user IDs, but we need internal UUIDs for the database
      const { UserService } = await import('@services/user.service');
      const userService = new UserService();
      
      const internalUserIds: string[] = [];
      for (const userIdOrOktaId of uniqueUserIds) {
        // Check if it's already a UUID (format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
        const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userIdOrOktaId);
        
        if (isUUID) {
          // Already a UUID, verify user exists
          const user = await User.findByPk(userIdOrOktaId);
          if (!user) {
            logger.warn(`[Summary] User with UUID ${userIdOrOktaId} not found, skipping`);
            continue;
          }
          internalUserIds.push(userIdOrOktaId);
        } else {
          // Likely an Okta ID, find user by oktaSub
          let user = await User.findOne({
            where: { oktaSub: userIdOrOktaId }
          });
          
          if (!user) {
            // User doesn't exist in database, try to fetch from Okta and create them
            // The userIdOrOktaId is the Okta ID, we need to fetch user info directly from Okta
            try {
              // First, try to fetch user directly from Okta by ID
              const oktaUser = await userService.fetchUserFromOktaById(userIdOrOktaId);
              
              if (oktaUser && oktaUser.status === 'ACTIVE') {
                // Ensure user exists in database
                const ensuredUser = await userService.ensureUserExists({
                  userId: oktaUser.id,
                  email: oktaUser.profile.email || oktaUser.profile.login,
                  displayName: oktaUser.profile.displayName || `${oktaUser.profile.firstName || ''} ${oktaUser.profile.lastName || ''}`.trim(),
                  firstName: oktaUser.profile.firstName,
                  lastName: oktaUser.profile.lastName,
                  department: oktaUser.profile.department,
                  phone: oktaUser.profile.mobilePhone
                });
                internalUserIds.push(ensuredUser.userId);
                logger.info(`[Summary] Created user ${ensuredUser.userId} from Okta ID ${userIdOrOktaId} for sharing`);
              } else {
                // Try to find by email if userIdOrOktaId looks like an email
                if (userIdOrOktaId.includes('@')) {
                  user = await User.findOne({
                    where: { email: userIdOrOktaId }
                  });
                  if (user) {
                    internalUserIds.push(user.userId);
                  } else {
                    logger.warn(`[Summary] User with email ${userIdOrOktaId} not found in database or Okta, skipping`);
                  }
                } else {
                  logger.warn(`[Summary] User with Okta ID ${userIdOrOktaId} not found in Okta or is inactive, skipping`);
                }
              }
            } catch (oktaError: any) {
              logger.error(`[Summary] Failed to fetch user from Okta for ${userIdOrOktaId}:`, oktaError);
              // Try to find by email if userIdOrOktaId looks like an email
              if (userIdOrOktaId.includes('@')) {
                user = await User.findOne({
                  where: { email: userIdOrOktaId }
                });
                if (user) {
                  internalUserIds.push(user.userId);
                } else {
                  logger.warn(`[Summary] User with email ${userIdOrOktaId} not found, skipping`);
                }
              } else {
                logger.warn(`[Summary] User with ID ${userIdOrOktaId} not found, skipping`);
              }
            }
          } else {
            internalUserIds.push(user.userId);
          }
        }
      }

      if (internalUserIds.length === 0) {
        throw new Error('No valid users found to share with');
      }

      // Create shared summary records
      const sharedSummaries: SharedSummary[] = [];
      for (const internalUserId of internalUserIds) {
        // Skip if already shared with this user
        const existing = await SharedSummary.findOne({
          where: {
            summaryId,
            sharedWith: internalUserId
          }
        });

        if (!existing) {
          const shared = await SharedSummary.create({
            summaryId,
            sharedBy,
            sharedWith: internalUserId,
            sharedAt: new Date(),
            isRead: false
          });
          sharedSummaries.push(shared);
        }
      }

      logger.info(`[Summary] Shared summary ${summaryId} with ${sharedSummaries.length} users`);
      return sharedSummaries;
    } catch (error) {
      logger.error(`[Summary] Failed to share summary ${summaryId}:`, error);
      throw error;
    }
  }

  /**
   * Get list of users who received shared summary for a specific summary
   * Only accessible by the initiator
   */
  async getSharedRecipients(summaryId: string, userId: string): Promise<any[]> {
    try {
      // Verify summary exists and user is the initiator
      const summary = await RequestSummary.findByPk(summaryId);
      if (!summary) {
        throw new Error('Summary not found');
      }

      if ((summary as any).initiatorId !== userId) {
        throw new Error('Only the initiator can view shared recipients');
      }

      // Get all shared summaries for this summary with user details
      const sharedSummaries = await SharedSummary.findAll({
        where: { summaryId },
        include: [
          {
            model: User,
            as: 'sharedWithUser',
            attributes: ['userId', 'email', 'displayName', 'designation', 'department']
          }
        ],
        order: [['sharedAt', 'DESC']]
      });

      // Format the response
      return sharedSummaries.map((shared: any) => {
        const user = (shared as any).sharedWithUser || {};
        return {
          userId: user.userId || (shared as any).sharedWith,
          email: user.email || 'N/A',
          displayName: user.displayName || 'Unknown',
          designation: user.designation || null,
          department: user.department || null,
          sharedAt: (shared as any).sharedAt,
          viewedAt: (shared as any).viewedAt,
          isRead: (shared as any).isRead || false
        };
      });
    } catch (error) {
      logger.error(`[Summary] Failed to get shared recipients for summary ${summaryId}:`, error);
      throw error;
    }
  }

  /**
   * List summaries shared with current user
   * userId can be either Okta ID or internal UUID - we'll convert to UUID
   */
  async listSharedSummaries(userId: string, page: number = 1, limit: number = 20): Promise<any> {
    try {
      // Convert Okta ID to internal UUID if needed
      let internalUserId = userId;
      
      // Check if it's already a UUID (format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
      const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(userId);
      
      if (!isUUID) {
        // Likely an Okta ID, find user by oktaSub
        const user = await User.findOne({
          where: { oktaSub: userId }
        });
        
        if (!user) {
          logger.warn(`[Summary] User with Okta ID ${userId} not found for listing shared summaries`);
          // Return empty result instead of error
          return {
            data: [],
            pagination: {
              page,
              limit,
              total: 0,
              totalPages: 0
            }
          };
        }
        
        internalUserId = user.userId;
      } else {
        // Verify UUID user exists
        const user = await User.findByPk(userId);
        if (!user) {
          logger.warn(`[Summary] User with UUID ${userId} not found for listing shared summaries`);
          return {
            data: [],
            pagination: {
              page,
              limit,
              total: 0,
              totalPages: 0
            }
          };
        }
      }

      const offset = (page - 1) * limit;

      const { rows, count } = await SharedSummary.findAndCountAll({
        where: { sharedWith: internalUserId },
        include: [
          {
            model: RequestSummary,
            as: 'summary',
            include: [
              {
                model: WorkflowRequest,
                as: 'request',
                attributes: ['requestId', 'requestNumber', 'title', 'status', 'closureDate']
              },
              {
                model: User,
                as: 'initiator',
                attributes: ['userId', 'email', 'displayName', 'designation']
              }
            ]
          },
          {
            model: User,
            as: 'sharedByUser',
            attributes: ['userId', 'email', 'displayName', 'designation']
          }
        ],
        order: [['sharedAt', 'DESC']],
        limit,
        offset
      });

      const summaries = rows.map((shared: any) => {
        const summary = (shared as any).summary;
        const request = summary?.request;
        const initiator = summary?.initiator;
        const sharedBy = (shared as any).sharedByUser;

        return {
          sharedSummaryId: (shared as any).sharedSummaryId,
          summaryId: (shared as any).summaryId,
          requestId: request?.requestId,
          requestNumber: request?.requestNumber || 'N/A',
          title: summary?.title || request?.title || 'N/A',
          initiatorName: initiator?.displayName || 'Unknown',
          sharedByName: sharedBy?.displayName || 'Unknown',
          sharedAt: (shared as any).sharedAt,
          viewedAt: (shared as any).viewedAt,
          isRead: (shared as any).isRead,
          closureDate: request?.closureDate
        };
      });

      return {
        data: summaries,
        pagination: {
          page,
          limit,
          total: count,
          totalPages: Math.ceil(count / limit) || 1
        }
      };
    } catch (error) {
      logger.error(`[Summary] Failed to list shared summaries for user ${userId}:`, error);
      throw error;
    }
  }

  /**
   * Mark shared summary as viewed
   */
  async markAsViewed(sharedSummaryId: string, userId: string): Promise<void> {
    try {
      const shared = await SharedSummary.findByPk(sharedSummaryId);
      if (!shared) {
        throw new Error('Shared summary not found');
      }

      if ((shared as any).sharedWith !== userId) {
        throw new Error('Access denied');
      }

      await shared.update({
        viewedAt: new Date(),
        isRead: true
      });

      logger.info(`[Summary] Marked shared summary ${sharedSummaryId} as viewed by user ${userId}`);
    } catch (error) {
      logger.error(`[Summary] Failed to mark shared summary as viewed:`, error);
      throw error;
    }
  }

  /**
   * List summaries created by user
   */
  async listMySummaries(userId: string, page: number = 1, limit: number = 20): Promise<any> {
    try {
      const offset = (page - 1) * limit;

      const { rows, count } = await RequestSummary.findAndCountAll({
        where: { initiatorId: userId },
        include: [
          {
            model: WorkflowRequest,
            as: 'request',
            attributes: ['requestId', 'requestNumber', 'title', 'status', 'closureDate']
          }
        ],
        order: [['createdAt', 'DESC']],
        limit,
        offset
      });

      const summaries = rows.map((summary: any) => {
        const request = (summary as any).request;
        return {
          summaryId: (summary as any).summaryId,
          requestId: request?.requestId,
          requestNumber: request?.requestNumber || 'N/A',
          title: (summary as any).title || request?.title || 'N/A',
          createdAt: (summary as any).createdAt,
          closureDate: request?.closureDate
        };
      });

      return {
        data: summaries,
        pagination: {
          page,
          limit,
          total: count,
          totalPages: Math.ceil(count / limit) || 1
        }
      };
    } catch (error) {
      logger.error(`[Summary] Failed to list summaries for user ${userId}:`, error);
      throw error;
    }
  }

  /**
   * Format status for display
   */
  private formatStatus(status: string): string {
    const statusMap: Record<string, string> = {
      'APPROVED': 'Approved',
      'REJECTED': 'Rejected',
      'PENDING': 'Pending',
      'IN_PROGRESS': 'In Progress',
      'SKIPPED': 'Skipped'
    };
    return statusMap[status.toUpperCase()] || status;
  }
}

export const summaryService = new SummaryService();

