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

export class ShoppingListsRepository {
  private sortItems(list: any) {
    if (!list || !list.items) return list;
    list.items.sort((a: any, b: any) => {
      // Unchecked first
      if (a.checked !== b.checked) return a.checked ? 1 : -1;
      // Then by category
      if (a.category !== b.category) return (a.category || '').localeCompare(b.category || '');
      // Then by name
      const nameA = a.customName || '';
      const nameB = b.customName || '';
      if (nameA !== nameB) return nameA.localeCompare(nameB);
      // Finally by ID
      return a.id.localeCompare(b.id);
    });
    return list;
  }

  public async create(data: any) {
    const list = new ShoppingListModel(data);
    const saved = await list.save();
    return this.sortItems(saved.toObject());
  }

  public async list(householdId: string) {
    const lists = await ShoppingListModel.find({ householdId })
      .sort({ createdAt: -1 })
      .lean()
      .exec();
    return lists.map((l) => this.sortItems(l));
  }

  public async findById(id: string, householdId: string) {
    const list = await ShoppingListModel.findOne({ _id: id, householdId }).lean().exec();
    return this.sortItems(list);
  }

  public async findActiveByHousehold(householdId: string) {
    const lists = await ShoppingListModel.find({
      householdId,
      status: { $in: ['active', 'shopping'] },
    })
      .sort({ updatedAt: -1 })
      .lean()
      .exec();
    return lists.map((l) => this.sortItems(l));
  }

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

  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) {
    const updated = await ShoppingListModel.findOneAndUpdate(
      { _id: id, householdId },
      { $push: { items: item } },
      { new: true },
    )
      .lean()
      .exec();
    return this.sortItems(updated);
  }

  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)) {
      setUpdates[`items.$.${key}`] = val;
    }

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

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