import { FreshnessRuleModel } from '../../schemas/freshness-rule.schema.js';

interface FindQuery {
  category?: string;
  storageLocation?: string;
  cursor?: string;
  limit: number;
}

export class FreshnessRulesRepository {
  public async findByHousehold(householdId: string, query: FindQuery) {
    const filter: Record<string, unknown> = {
      $or: [{ householdId }, { householdId: { $exists: false } }, { householdId: null }],
    };

    if (query.category) filter['category'] = query.category;
    if (query.storageLocation) filter['storageLocation'] = query.storageLocation;

    if (query.cursor) {
      const id = Buffer.from(query.cursor, 'base64').toString();
      filter['_id'] = { $gt: id };
    }

    const limit = query.limit;
    const items = await FreshnessRuleModel.find(filter)
      .sort({ category: 1, storageLocation: 1, _id: 1 })
      .limit(limit + 1)
      .lean()
      .exec();

    const hasMore = items.length > limit;
    const data = hasMore ? items.slice(0, limit) : items;
    const cursor =
      data.length > 0
        ? Buffer.from(data[data.length - 1]!._id.toString()).toString('base64')
        : null;

    return { data, pagination: { cursor: hasMore ? cursor : null, hasMore } };
  }

  public async findById(id: string) {
    return FreshnessRuleModel.findById(id).lean().exec();
  }

  public async findApplicableRule(householdId: string, category: string, storageLocation: string) {
    // Household override takes priority
    const householdRule = await FreshnessRuleModel.findOne({
      householdId,
      category,
      storageLocation,
    })
      .lean()
      .exec();

    if (householdRule) return householdRule;

    // Fall back to system default
    return FreshnessRuleModel.findOne({
      $or: [{ householdId: null }, { householdId: { $exists: false } }],
      category,
      storageLocation,
    })
      .lean()
      .exec();
  }

  public async create(data: Record<string, unknown>) {
    const doc = new FreshnessRuleModel(data);
    const saved = await doc.save();
    return saved.toObject();
  }

  public async update(id: string, householdId: string, data: Record<string, unknown>) {
    return FreshnessRuleModel.findOneAndUpdate(
      { _id: id, householdId },
      { $set: data },
      { new: true },
    )
      .lean()
      .exec();
  }

  public async delete(id: string, householdId: string) {
    return FreshnessRuleModel.findOneAndDelete({ _id: id, householdId }).exec();
  }
}
