import {
  BadRequestException,
  Injectable,
  NotFoundException,
} from "@nestjs/common";
import { InjectModel } from "@nestjs/mongoose";
import { Model, Types } from "mongoose";
import { Attachment, AttachmentDocument } from "src/schema/attachment.schema";
import { StoragesService } from "src/storage/storage.service";
import { ResponseService } from "src/common/service/response.service";
import { Response } from "express";
import { existsSync, unlinkSync } from "fs";
@Injectable()
export class AttachmentService {
  constructor(
    @InjectModel(Attachment.name)
    private attachmentModel: Model<AttachmentDocument>,
    private readonly s3StorageService: StoragesService,
    private readonly resService: ResponseService,

  ) {}

  /**
   * =============================
   * CREATE ATTACHMENT
   * =============================
   */
  async uploadAttachment(
    file: Express.Multer.File,
    options: {
      entityType: "expense" | "invoice" | "estimate" | "profile";
      entityId: string;
      userId: string;
    },
  ) {
    if (!file) {
      throw new BadRequestException("File not provided");
    }

    const { entityType, entityId, userId } = options;

    // Sanitize filename
    const sanitizedFileName = file.originalname.replace(/\s+/g, "-");

    // S3 path structure
    const path = `users/${userId}/${entityType}/${entityId}/${Date.now()}-${sanitizedFileName}`;

    // Upload to S3
    const key = await this.s3StorageService.upload(
      file.buffer,
      path,
      file.mimetype,
    );

    // Generate URL (or use signed URL later)
    const fileUrl = await this.s3StorageService.getUrl(key);
   

    // Save metadata in DB
    const attachment = await this.attachmentModel.create({
      userId: new Types.ObjectId(userId),
      entityType,
      entityId: new Types.ObjectId(entityId),
      fileUrl,
      fileName: file.originalname,
      fileType: file.mimetype,
      fileSize: file.size,
    });
   

    return attachment;
  }

async uploadBufferAttachment(
  buffer: Buffer,
  fileName: string,
  mimeType: string,
  options: {
    entityType:
      | "expense"
      | "invoice"
      | "estimate"
      | "profile"
      | "invoice-template"
      | "estimate-template";
    entityId: string;
    userId: string;
  },
) {
  const { entityType, entityId, userId } = options;

  const objectEntityId = new Types.ObjectId(entityId);
  const objectUserId = new Types.ObjectId(userId);

  const sanitizedFileName = fileName.replace(/\s+/g, "-");

  const shortUserId = userId.slice(-6);
  const shortEntityId = entityId.slice(-6);

  const path = `u/${shortUserId}/${entityType}/${shortEntityId}/${Date.now()}-${sanitizedFileName}`;

  const key = await this.s3StorageService.upload(buffer, path, mimeType);

  const fileUrl = await this.s3StorageService.getUrl(key);

  /**
   * ✅ STEP 3: Save new attachment
   */
  const attachment = await this.attachmentModel.create({
    userId: objectUserId,
    entityType,
    entityId: objectEntityId,
    fileUrl,
    fileName,
    fileType: mimeType,
    fileSize: buffer.length,
  });

  return attachment;
}


async deleteExistingInvoiceTemplates(invoiceId: string, userId: string) {
  const objectEntityId = new Types.ObjectId(invoiceId);
  const objectUserId = new Types.ObjectId(userId);

  const existingTemplates = await this.attachmentModel.find({
    entityType: "invoice-template",
    entityId: objectEntityId,
    userId: objectUserId,
  });

  await Promise.all(
    existingTemplates.map(async (oldTemplate) => {
      await this.s3StorageService.delete(oldTemplate.fileUrl);
      await this.attachmentModel.deleteOne({ _id: oldTemplate._id });
    }),
  );
}

async deleteExistingEstimateTemplates(estimateId: string, userId: string) {
  const objectEntityId = new Types.ObjectId(estimateId);
  const objectUserId = new Types.ObjectId(userId);

  const existingTemplates = await this.attachmentModel.find({
    entityType: "estimate-template",
    entityId: objectEntityId,
    userId: objectUserId,
  });

  await Promise.all(
    existingTemplates.map(async (oldTemplate) => {
      await this.s3StorageService.delete(oldTemplate.fileUrl);
      await this.attachmentModel.deleteOne({ _id: oldTemplate._id });
    }),
  );
}


// async uploadBufferAttachment(
//   buffer: Buffer,
//   fileName: string,
//   mimeType: string,
//   options: {
//     entityType:
//       | "expense"
//       | "invoice"
//       | "estimate"
//       | "profile"
//       | "invoice-template"
//       | "estimate-template";
//     entityId: string;
//     userId: string;
//   },
// ) {
//   const { entityType, entityId, userId } = options;

//   const objectEntityId = new Types.ObjectId(entityId);
//   const objectUserId = new Types.ObjectId(userId);

//   /**
//    * ✅ STEP 1: If template → delete previous
//    */
//   if (
//     entityType === "invoice-template" ||
//     entityType === "estimate-template"
//   ) {
//     const existingTemplates = await this.attachmentModel.find({
//       entityType,
//       entityId: objectEntityId,
//       userId: objectUserId,
//     });

//     for (const oldTemplate of existingTemplates) {
//       // Delete from S3
//       await this.s3StorageService.delete(oldTemplate.fileUrl);

//       // Delete from DB
//       await this.attachmentModel.deleteOne({ _id: oldTemplate._id });
//     }
//   }

//   /**
//    * ✅ STEP 2: Upload new file
//    */
//   const sanitizedFileName = fileName.replace(/\s+/g, "-");

//   const shortUserId = userId.slice(-6);
//   const shortEntityId = entityId.slice(-6);

//   const path = `u/${shortUserId}/${entityType}/${shortEntityId}/${Date.now()}-${sanitizedFileName}`;

//   const key = await this.s3StorageService.upload(buffer, path, mimeType);

//   const fileUrl = await this.s3StorageService.getUrl(key);

//   /**
//    * ✅ STEP 3: Save new attachment
//    */
//   const attachment = await this.attachmentModel.create({
//     userId: objectUserId,
//     entityType,
//     entityId: objectEntityId,
//     fileUrl,
//     fileName,
//     fileType: mimeType,
//     fileSize: buffer.length,
//   });

//   return attachment;
// }

  /**
   * =============================
   * GET ATTACHMENTS BY ENTITY
   * =============================
   */
  async getAttachments(entityType: string, entityId: string) {
    return this.attachmentModel.find({
      entityType,
      entityId: new Types.ObjectId(entityId),
    });
  }


 


  
  
  // async deleteAttachment() {
   
  //   // Delete from S3
  //   // await this.s3StorageService.delete();

   

  //   return { message: "Attachment deleted successfully" };
  // }




  async deleteAttachment(
  userId: string,
  attachmentId: string,
  res: Response,
) {
  try {
    const userObjectId = new Types.ObjectId(userId);

    const attachment = await this.attachmentModel.findOne({
      _id: new Types.ObjectId(attachmentId),
      userId: userObjectId,
    });

    if (!attachment) {
      return this.resService.notFound(res, "Attachment not found");
    }

     if (existsSync(attachment.fileUrl)) {
        unlinkSync(attachment.fileUrl);
      }

    //  Delete from storage first
    // await this.storageService.deleteFile({
    //   fileUrl: attachment.fileUrl,
    //   key: attachment.key, // if you store S3 key
    // });

    //  Delete from DB
    await attachment.deleteOne();

    return this.resService.success(
      res,
      null,
      "Attachment deleted successfully",
    );
  } catch (error) {
    return this.resService.serverError(
      res,
      "Failed to delete attachment",
      error,
    );
  }
}



async getListAttachments() {
    return this.s3StorageService.getListFiles();
  }

  /**
   * =============================
   * HELPER
   * =============================
   */
  private extractKeyFromUrl(url: string): string {
    const bucketUrlPart = url.split(".amazonaws.com/")[1];
    return bucketUrlPart;
  }
}
