import { Injectable, Logger, NotFoundException, ForbiddenException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { S3Service } from '../s3/s3.service';
import { Document, User, Prisma } from '@prisma/client';
import { EmailService } from '../email/email.service';

@Injectable()
export class DocumentsService {
  private readonly logger = new Logger(DocumentsService.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly s3Service: S3Service,
    private readonly emailService: EmailService,
  ) {
    this.logger.log('DocumentsService initialized with EmailService');
    this.logger.debug('EmailService instance:', {
      exists: !!this.emailService,
      type: typeof this.emailService,
      methods: Object.keys(Object.getPrototypeOf(this.emailService)),
    });
  }

  async findDocumentByS3Key(s3Key: string) {
    return this.prisma.document.findFirst({
      where: { s3Key },
      include: {
        uploadedBy: true,
        sharedWith: true,
      },
    });
  }

  async verifyDocumentAccess(documentId: number, userId: number): Promise<boolean> {
    const document = await this.prisma.document.findUnique({
      where: { id: documentId },
      include: {
        uploadedBy: true,
        sharedWith: {
          where: {
            id: userId
          }
        }
      },
    });

    if (!document) {
      return false;
    }

    // User has access if they uploaded the document or it's shared with them
    return document.uploadedBy.id === userId || document.sharedWith.length > 0;
  }

  async getClientDocuments(clientId: number) {
    return this.prisma.document.findMany({
      where: {
        OR: [
          { uploadedById: clientId },
          { 
            sharedWith: {
              some: {
                id: clientId
              }
            } 
          }
        ]
      },
      include: {
        uploadedBy: {
          select: {
            id: true,
            name: true,
            email: true
          }
        },
        sharedWith: {
          select: {
            id: true,
            name: true,
            email: true
          }
        }
      },
      orderBy: {
        createdAt: 'desc'
      }
    });
  }

  async uploadDocument(
    file: Express.Multer.File,
    title: string,
    sharedWithId: number,
    uploadedById: number
  ) {
    this.logger.log('=== Starting document upload process ===');
    this.logger.debug('Upload parameters:', {
      title,
      sharedWithId,
      uploadedById,
      fileName: file.originalname,
      fileSize: file.size,
    });
    
    try {
      this.logger.debug('Uploading file to S3...');
      const s3Key = await this.s3Service.uploadFile(file, 'documents');
      this.logger.debug(`File uploaded to S3 successfully with key: ${s3Key}`);
      
      this.logger.debug('Creating document record in database...');
      const document = await this.prisma.document.create({
        data: {
          title,
          s3Key,
          status: 'pending',
          uploadedBy: {
            connect: { id: uploadedById }
          },
          sharedWith: {
            connect: { id: sharedWithId }
          }
        },
        include: {
          uploadedBy: {
            select: {
              id: true,
              name: true,
              email: true,
            },
          },
          sharedWith: {
            select: {
              id: true,
              name: true,
              email: true,
            },
          },
        },
      });
      this.logger.debug('Document record created:', {
        id: document.id,
        title: document.title,
        uploadedBy: document.uploadedBy,
        sharedWith: document.sharedWith,
      });

      // Send email notifications
      this.logger.log('=== Starting email notification process ===');
      
      // Notify the user who the document is shared with
      const sharedUser = document.sharedWith[0];
      if (sharedUser) {
        this.logger.debug(`Preparing to send notification to shared user:`, {
          id: sharedUser.id,
          email: sharedUser.email,
          name: sharedUser.name,
        });
        try {
          this.logger.debug('Calling EmailService.sendDocumentNotification for shared user...');
          await this.emailService.sendDocumentNotification(
            sharedUser.email,
            sharedUser.name,
            document.title,
            'shared'
          );
          this.logger.debug('Shared user notification sent successfully');
        } catch (error) {
          this.logger.error('Failed to send notification to shared user:', {
            error: error.message,
            code: error.code,
            command: error.command,
            stack: error.stack,
          });
          // Log the email service instance to verify it's properly injected
          this.logger.debug('EmailService instance:', {
            exists: !!this.emailService,
            type: typeof this.emailService,
            methods: Object.keys(Object.getPrototypeOf(this.emailService)),
          });
        }
      } else {
        this.logger.warn('No shared user found in the document record');
      }

      // Notify the uploader
      const uploader = document.uploadedBy;
      if (uploader) {
        this.logger.debug(`Preparing to send notification to uploader:`, {
          id: uploader.id,
          email: uploader.email,
          name: uploader.name,
        });
        try {
          this.logger.debug('Calling EmailService.sendDocumentNotification for uploader...');
          await this.emailService.sendDocumentNotification(
            uploader.email,
            uploader.name,
            document.title,
            'uploaded'
          );
          this.logger.debug('Uploader notification sent successfully');
        } catch (error) {
          this.logger.error('Failed to send notification to uploader:', {
            error: error.message,
            code: error.code,
            command: error.command,
            stack: error.stack,
          });
          // Log the email service instance to verify it's properly injected
          this.logger.debug('EmailService instance:', {
            exists: !!this.emailService,
            type: typeof this.emailService,
            methods: Object.keys(Object.getPrototypeOf(this.emailService)),
          });
        }
      } else {
        this.logger.warn('No uploader found in the document record');
      }

      this.logger.log('=== Document upload process completed ===');
      return document;
    } catch (error) {
      this.logger.error('Error in uploadDocument:', {
        error: error.message,
        code: error.code,
        stack: error.stack,
      });
      throw error;
    }
  }
}
