import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { S3Service } from '../s3/s3.service';
import { UpdateDocumentDto } from '../dto/update-document.dto';
import { CreateUserDto } from '../dto/create-user.dto';
import * as bcrypt from 'bcrypt';
import { EmailService } from '../email/email.service';
import { AuthService } from '../auth/auth.service';

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

  constructor(
    private readonly prisma: PrismaService,
    private readonly s3Service: S3Service,
    private readonly emailService: EmailService,
    private readonly authService: AuthService,
  ) {}

  async getAllDocuments() {
    return this.prisma.document.findMany({
      include: {
        uploadedBy: {
          select: {
            id: true,
            name: true,
            email: true,
          },
        },
        sharedWith: {
          select: {
            id: true,
            name: true,
            email: true,
          },
        },
      },
      orderBy: {
        createdAt: 'desc',
      },
    });
  }

  async getAllUsers() {
    return this.prisma.user.findMany();
  }

  async createUser(createUserDto: CreateUserDto) {
    this.logger.log('Delegating user creation to AuthService');
    return this.authService.createUser(createUserDto, createUserDto.isAdmin);
  }

  async updateDocument(
    id: number,
    updateDocumentDto: UpdateDocumentDto,
    file?: Express.Multer.File,
  ) {
    let s3Key = undefined;
    if (file) {
      s3Key = await this.s3Service.uploadFile(file, 'documents');
    }

    return this.prisma.document.update({
      where: { id },
      data: {
        ...updateDocumentDto,
        ...(s3Key && { s3Key }),
      },
    });
  }

  async shareDocument(documentId: number, userId: number) {
    this.logger.log('=== Starting document share process ===');
    console.log('=== Starting document share process ===');
    this.logger.debug('Share request:', { documentId, userId });
    console.log('Share request:', { documentId, userId });

    try {
      // Get the document with its current data
      const document = await this.prisma.document.findUnique({
        where: { id: documentId },
        include: {
          uploadedBy: {
            select: {
              id: true,
              name: true,
              email: true,
            },
          },
        },
      });

      if (!document) {
        this.logger.error('Document not found:', { documentId });
        console.error('Document not found:', { documentId });
        throw new Error('Document not found');
      }

      // Get the user we're sharing with
      const shareUser = await this.prisma.user.findUnique({
        where: { id: userId },
        select: {
          id: true,
          name: true,
          email: true,
        },
      });

      if (!shareUser) {
        this.logger.error('User not found:', { userId });
        console.error('User not found:', { userId });
        throw new Error('User not found');
      }

      // Update the document sharing
      const updatedDocument = await this.prisma.document.update({
        where: { id: documentId },
        data: {
          sharedWith: {
            connect: { id: userId },
          },
        },
        include: {
          uploadedBy: {
            select: {
              id: true,
              name: true,
              email: true,
            },
          },
          sharedWith: {
            select: {
              id: true,
              name: true,
              email: true,
            },
          },
        },
      });

      // Send email notification to the user we're sharing with
      this.logger.log('Sending email notification to shared user:', {
        userId: shareUser.id,
        email: shareUser.email,
        name: shareUser.name,
        documentTitle: document.title
      });
      console.log('Sending email notification to shared user:', {
        userId: shareUser.id,
        email: shareUser.email,
        name: shareUser.name,
        documentTitle: document.title
      });

      try {
        console.log('Attempting to send email notification...');
        await this.emailService.sendDocumentNotification(
          shareUser.email,
          shareUser.name,
          document.title,
          'shared'
        );
        console.log('Email notification sent successfully');
        this.logger.log('Email notification sent successfully');
      } catch (emailError) {
        // Log the full error details
        console.error('Failed to send email notification:', emailError);
        this.logger.error('Failed to send email notification:', {
          error: emailError.message,
          code: emailError.code,
          command: emailError.command,
          response: emailError.response,
          responseCode: emailError.responseCode,
          stack: emailError.stack,
        });
        // Don't throw the error, just log it and continue
      }

      this.logger.log('=== Document share process completed ===');
      console.log('=== Document share process completed ===');
      return updatedDocument;
    } catch (error) {
      this.logger.error('Error in shareDocument:', {
        error: error.message,
        code: error.code,
        stack: error.stack,
      });
      console.error('Error in shareDocument:', error);
      throw error;
    }
  }

  async updateDocumentStatus(documentId: number, status: string) {
    return this.prisma.document.update({
      where: { id: documentId },
      data: { status },
    });
  }

  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',
          sharedWith: {
            connect: { id: sharedWithId }
          },
          uploadedBy: {
            connect: { id: uploadedById }
          }
        },
        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;
    }
  }

  async resetUserPassword(userId: number, newPassword: string) {
    this.logger.log('=== Starting password reset process ===');
    this.logger.debug('Reset request for user:', { userId });

    try {
      // Find the user
      const user = await this.prisma.user.findUnique({
        where: { id: userId },
        select: {
          id: true,
          email: true,
          name: true,
        },
      });

      if (!user) {
        this.logger.error('User not found:', { userId });
        throw new NotFoundException('User not found');
      }

      // Hash the new password
      const hashedPassword = await bcrypt.hash(newPassword, 10);

      // Update the user's password
      await this.prisma.user.update({
        where: { id: userId },
        data: { password: hashedPassword },
      });

      this.logger.log('Password reset successful for user:', {
        userId: user.id,
        email: user.email,
      });

      // Send email notification
      try {
        await this.emailService.sendPasswordResetNotification(
          user.email,
          user.name
        );
        this.logger.debug('Password reset notification sent');
      } catch (emailError) {
        this.logger.error('Failed to send password reset notification:', {
          error: emailError.message,
          code: emailError.code,
          stack: emailError.stack,
        });
        // Don't throw the error, just log it
      }

      return { message: 'Password reset successful' };
    } catch (error) {
      this.logger.error('Error in resetUserPassword:', {
        error: error.message,
        code: error.code,
        stack: error.stack,
      });
      throw error;
    }
  }
}