import { Op } from 'sequelize';
import { WorkNote } from '@models/WorkNote';
import { WorkNoteAttachment } from '@models/WorkNoteAttachment';
import { Participant } from '@models/Participant';
import { WorkflowRequest } from '@models/WorkflowRequest';
import { activityService } from './activity.service';
import { notificationService } from './notification.service';
import logger from '@utils/logger';

export class WorkNoteService {
  async list(requestId: string) {
    const notes = await WorkNote.findAll({
      where: { requestId },
      order: [['created_at' as any, 'ASC']]
    });

    // Load attachments for each note
    const enriched = await Promise.all(notes.map(async (note) => {
      const noteId = (note as any).noteId;
      const attachments = await WorkNoteAttachment.findAll({
        where: { noteId }
      });
      
      const noteData = (note as any).toJSON();
      
      const mappedAttachments = attachments.map((a: any) => {
        const attData = typeof a.toJSON === 'function' ? a.toJSON() : a;
        return {
          attachmentId: attData.attachmentId || attData.attachment_id,
          fileName: attData.fileName || attData.file_name,
          fileType: attData.fileType || attData.file_type,
          fileSize: attData.fileSize || attData.file_size,
          filePath: attData.filePath || attData.file_path,
          storageUrl: attData.storageUrl || attData.storage_url,
          isDownloadable: attData.isDownloadable || attData.is_downloadable,
          uploadedAt: attData.uploadedAt || attData.uploaded_at
        };
      });
      
      return {
        noteId: noteData.noteId || noteData.note_id,
        requestId: noteData.requestId || noteData.request_id,
        userId: noteData.userId || noteData.user_id,
        userName: noteData.userName || noteData.user_name,
        userRole: noteData.userRole || noteData.user_role,
        message: noteData.message,
        isPriority: noteData.isPriority || noteData.is_priority,
        hasAttachment: noteData.hasAttachment || noteData.has_attachment,
        createdAt: noteData.createdAt || noteData.created_at,
        updatedAt: noteData.updatedAt || noteData.updated_at,
        attachments: mappedAttachments
      };
    }));

    return enriched;
  }

  async getUserRole(requestId: string, userId: string): Promise<string> {
    try {
      const participant = await Participant.findOne({
        where: { requestId, userId }
      });
      if (participant) {
        const type = (participant as any).participantType || (participant as any).participant_type;
        return type ? type.toString() : 'Participant';
      }
      return 'Participant';
    } catch (error) {
      logger.error('[WorkNote] Error fetching user role:', error);
      return 'Participant';
    }
  }

  async create(requestId: string, user: { userId: string; name?: string; role?: string }, payload: { message: string; isPriority?: boolean; parentNoteId?: string | null; mentionedUsers?: string[] | null; }, files?: Array<{ path: string; originalname: string; mimetype: string; size: number }>, requestMetadata?: { ipAddress?: string | null; userAgent?: string | null }): Promise<any> {
    logger.info('[WorkNote] Creating note:', { requestId, user, messageLength: payload.message?.length });
    
    const note = await WorkNote.create({
      requestId,
      userId: user.userId,
      userName: user.name || null,
      userRole: user.role || null, // Store participant type (INITIATOR/APPROVER/SPECTATOR)
      message: payload.message,
      isPriority: !!payload.isPriority,
      parentNoteId: payload.parentNoteId || null,
      mentionedUsers: payload.mentionedUsers || null,
      hasAttachment: files && files.length > 0 ? true : false
    } as any);
    
    logger.info('[WorkNote] Created note:', { 
      noteId: (note as any).noteId, 
      userId: (note as any).userId, 
      userName: (note as any).userName,
      userRole: (note as any).userRole
    });

    const attachments = [];
    if (files && files.length) {
      for (const f of files) {
        const attachment = await WorkNoteAttachment.create({
          noteId: (note as any).noteId,
          fileName: f.originalname,
          fileType: f.mimetype,
          fileSize: f.size,
          filePath: f.path,
          isDownloadable: true
        } as any);
        
        attachments.push({
          attachmentId: (attachment as any).attachmentId,
          fileName: (attachment as any).fileName,
          fileType: (attachment as any).fileType,
          fileSize: (attachment as any).fileSize,
          filePath: (attachment as any).filePath,
          isDownloadable: (attachment as any).isDownloadable
        });
      }
    }

    // Log activity for work note
    activityService.log({
      requestId,
      type: 'comment',
      user: { userId: user.userId, name: user.name || 'User' },
      timestamp: new Date().toISOString(),
      action: 'Work Note Added',
      details: `${user.name || 'User'} added a work note: ${payload.message.substring(0, 100)}${payload.message.length > 100 ? '...' : ''}`,
      ipAddress: requestMetadata?.ipAddress || undefined,
      userAgent: requestMetadata?.userAgent || undefined
    });

    try {
      // Optional realtime emit (if socket layer is initialized)
      const { emitToRequestRoom } = require('../realtime/socket');
      if (emitToRequestRoom) {
        // Emit note with all fields explicitly (to ensure camelCase fields are sent)
        const noteData = {
          noteId: (note as any).noteId,
          requestId: (note as any).requestId,
          userId: (note as any).userId,
          userName: (note as any).userName,
          userRole: (note as any).userRole, // Include participant role
          message: (note as any).message,
          createdAt: (note as any).createdAt,
          hasAttachment: (note as any).hasAttachment,
          attachments: attachments // Include attachments
        };
        emitToRequestRoom(requestId, 'worknote:new', { note: noteData });
      }
    } catch (e) { logger.warn('Realtime emit failed (not initialized)'); }

    // Send notifications to mentioned users
    if (payload.mentionedUsers && Array.isArray(payload.mentionedUsers) && payload.mentionedUsers.length > 0) {
      try {
        // Get workflow details for request number and title
        const workflow = await WorkflowRequest.findOne({ where: { requestId } });
        const requestNumber = (workflow as any)?.requestNumber || requestId;
        const requestTitle = (workflow as any)?.title || 'Request';
        
        logger.info(`[WorkNote] Sending mention notifications to ${payload.mentionedUsers.length} users`);
        
        await notificationService.sendToUsers(
          payload.mentionedUsers,
          {
            title: '💬 Mentioned in Work Note',
            body: `${user.name || 'Someone'} mentioned you in ${requestNumber}: "${payload.message.substring(0, 50)}${payload.message.length > 50 ? '...' : ''}"`,
            requestId,
            requestNumber,
            url: `/request/${requestNumber}`,
            type: 'mention'
          }
        );
        
        logger.info(`[WorkNote] Mention notifications sent successfully`);
      } catch (notifyError) {
        logger.error('[WorkNote] Failed to send mention notifications:', notifyError);
        // Don't fail the work note creation if notifications fail
      }
    }

    return { ...note, attachments };
  }

  async downloadAttachment(attachmentId: string) {
    const attachment = await WorkNoteAttachment.findOne({
      where: { attachmentId }
    });
    
    if (!attachment) {
      throw new Error('Attachment not found');
    }

    return {
      filePath: (attachment as any).filePath,
      fileName: (attachment as any).fileName,
      fileType: (attachment as any).fileType
    };
  }
}

export const workNoteService = new WorkNoteService();


