import { ShoppingListModel } from '../../schemas/shopping-list.schema.js';
import type {
  CreateShoppingListInput,
  UpdateShoppingListInput,
  ShoppingItem,
} from '@meshitrack/shared';

export class ShoppingListsRepository {
  public async create(data: CreateShoppingListInput & { householdId: string; createdBy: string; status: string }) {
    const list = new ShoppingListModel(data);
    const saved = await list.save();
    return saved.toObject();
  }

  public async list(householdId: string) {
    return ShoppingListModel.find({ householdId })
      .sort({ createdAt: -1 })
      .lean()
      .exec();
  }

  public async findById(id: string, householdId: string) {
    return ShoppingListModel.findOne({ _id: id, householdId }).lean().exec();
  }

  public async findActiveByHousehold(householdId: string) {
    return ShoppingListModel.find({ householdId, status: { $in: ['active', 'shopping'] } })
      .sort({ updatedAt: -1 })
      .lean()
      .exec();
  }

  public async update(id: string, householdId: string, data: UpdateShoppingListInput) {
    return ShoppingListModel.findOneAndUpdate(
      { _id: id, householdId },
      { $set: data },
      { new: true }
    ).lean().exec();
  }

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

  // --- Granular Atomic Subdocument Actions ---

  public async addItem(id: string, householdId: string, item: ShoppingItem) {
    return ShoppingListModel.findOneAndUpdate(
      { _id: id, householdId },
      { $push: { items: item } },
      { new: true }
    ).lean().exec();
  }

  public async updateItem(
    id: string,
    householdId: string,
    itemId: string,
    updates: Partial<ShoppingItem>
  ) {
    const setUpdates: Record<string, unknown> = {};
    for (const [key, val] of Object.entries(updates)) {
      // Flatten parameters mapping them precisely to the positional positional matched index
      setUpdates[`items.$.${key}`] = val;
    }

    return ShoppingListModel.findOneAndUpdate(
      { _id: id, householdId, 'items.id': itemId },
      { $set: setUpdates },
      { new: true }
    ).lean().exec();
  }

  public async removeItem(id: string, householdId: string, itemId: string) {
    return ShoppingListModel.findOneAndUpdate(
      { _id: id, householdId },
      { $pull: { items: { id: itemId } } },
      { new: true }
    ).lean().exec();
  }
}
