import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model, Types } from 'mongoose';
import { Save, SaveDocument } from './schemas/save.schema';

@Injectable()
export class SavesRepository {
  constructor(@InjectModel(Save.name) private readonly saveModel: Model<SaveDocument>) {}

  async findOne(userId: string, postId: string): Promise<SaveDocument | null> {
    return this.saveModel
      .findOne({ userId: new Types.ObjectId(userId), postId: new Types.ObjectId(postId) })
      .exec();
  }

  async create(userId: string, postId: string): Promise<SaveDocument> {
    return this.saveModel.create({
      userId: new Types.ObjectId(userId),
      postId: new Types.ObjectId(postId),
    });
  }

  async createIfAbsent(userId: string, postId: string): Promise<boolean> {
    const result = await this.saveModel
      .updateOne(
        { userId: new Types.ObjectId(userId), postId: new Types.ObjectId(postId) },
        { $setOnInsert: { userId: new Types.ObjectId(userId), postId: new Types.ObjectId(postId) } },
        { upsert: true },
      )
      .exec();
    return result.upsertedCount === 1;
  }

  async findSavedPostIds(userId: string, postIds: string[]): Promise<string[]> {
    if (!postIds.length) {
      return [];
    }

    const rows = await this.saveModel
      .find({
        userId: new Types.ObjectId(userId),
        postId: { $in: postIds.map((id) => new Types.ObjectId(id)) },
      })
      .select({ postId: 1 })
      .lean()
      .exec();

    return rows.map((row) => row.postId.toString());
  }

  async deleteById(id: string): Promise<boolean> {
    const deleted = await this.saveModel.findByIdAndDelete(id).exec();
    return !!deleted;
  }

  async findUserSavedPostIds(
    userId: string,
    skip: number,
    limit: number,
    sort: Record<string, 1 | -1> = { createdAt: -1 },
  ): Promise<string[]> {
    const rows = await this.saveModel
      .find({ userId: new Types.ObjectId(userId) })
      .sort(sort)
      .skip(skip)
      .limit(limit)
      .select('postId')
      .exec();

    return rows.map((row) => row.postId.toString());
  }

  async countByUser(userId: string): Promise<number> {
    return this.saveModel.countDocuments({ userId: new Types.ObjectId(userId) }).exec();
  }
}
