import { RecordModel } from 'pocketbase';
import { pb } from './pocketbase';
import { syncQueue, isOfflineError } from '../lib/syncQueue';
import { ShoppingListEntry } from '../types';
import { updateItemQuantity } from './items';
import { sendShoppingListPush } from './notifications';

function mapShoppingRecord(r: RecordModel): ShoppingListEntry {
  return {
    id: r.id,
    itemId: r.item_id || null,
    name: r.name,
    suggestedQuantity: r.suggested_quantity ?? 1,
    unit: r.unit ?? '',
    isChecked: r.is_checked ?? false,
    checkedByDevice: r.checked_by_device || null,
    autoAdded: r.auto_added ?? false,
    createdAt: new Date(r.created),
  };
}

function getStore() {
  const { useHouseholdStore } = require('../hooks/useHousehold');
  return useHouseholdStore.getState();
}

export async function addToShoppingList(
  householdId: string,
  entry: Omit<ShoppingListEntry, 'id' | 'createdAt' | 'isChecked' | 'checkedByDevice'>
): Promise<void> {
  const store = getStore();
  const optimistic: ShoppingListEntry = {
    ...entry,
    id: 'offline_' + Date.now(),
    isChecked: false,
    checkedByDevice: null,
    createdAt: new Date(),
  };
  store.setShoppingList([...store.shoppingList, optimistic]);

  try {
    await pb.collection('shopping_list').create({
      household: householdId,
      item_id: entry.itemId ?? null,
      name: entry.name,
      suggested_quantity: entry.suggestedQuantity,
      unit: entry.unit,
      is_checked: false,
      auto_added: entry.autoAdded,
    });
    sendShoppingListPush(householdId, entry.name);
  } catch (e) {
    if (isOfflineError(e)) {
      await syncQueue.add({ type: 'addToShoppingList', payload: { householdId, entry } });
    } else throw e;
  }
}

export async function checkOffItem(
  householdId: string,
  entryId: string,
  deviceId: string,
  quantityBought: number
): Promise<void> {
  const store = getStore();
  const entry = store.shoppingList.find((e: ShoppingListEntry) => e.id === entryId);
  if (!entry) return;

  store.setShoppingList(
    store.shoppingList.map((e: ShoppingListEntry) =>
      e.id === entryId ? { ...e, isChecked: true, checkedByDevice: deviceId } : e
    )
  );

  try {
    // Mark is_checked FIRST so server hook (which filters is_checked=false) won't delete the entry
    await pb.collection('shopping_list').update(entryId, {
      is_checked: true,
      checked_by_device: deviceId,
    });
    // Then update quantity — server hook finds no is_checked=false entries to delete
    if (entry.itemId) {
      const itemRecord = await pb.collection('items').getOne(entry.itemId);
      const currentQty = (itemRecord.quantity as number) ?? 0;
      await updateItemQuantity(householdId, entry.itemId, currentQty + quantityBought);
    }
  } catch (e) {
    if (isOfflineError(e)) {
      await syncQueue.add({
        type: 'checkOffItem',
        payload: { householdId, entryId, deviceId, quantityBought },
      });
    } else throw e;
  }
}

export async function clearCheckedItems(householdId: string): Promise<void> {
  const store = getStore();
  store.setShoppingList(store.shoppingList.filter((e: ShoppingListEntry) => !e.isChecked));

  try {
    const checked = await pb.collection('shopping_list').getFullList({
      filter: `household = "${householdId}" && is_checked = true`,
    });
    await Promise.all(checked.map((e) => pb.collection('shopping_list').delete(e.id)));
  } catch (e) {
    if (isOfflineError(e)) {
      await syncQueue.add({ type: 'clearCheckedItems', payload: { householdId } });
    } else throw e;
  }
}

export async function removeShoppingEntry(householdId: string, entryId: string): Promise<void> {
  const store = getStore();
  store.setShoppingList(store.shoppingList.filter((e: ShoppingListEntry) => e.id !== entryId));

  try {
    await pb.collection('shopping_list').delete(entryId);
  } catch (e) {
    if (isOfflineError(e)) {
      await syncQueue.add({ type: 'removeShoppingEntry', payload: { householdId, entryId } });
    } else throw e;
  }
}

export function subscribeToShoppingList(
  householdId: string,
  onChange: (entries: ShoppingListEntry[]) => void
): () => void {
  let current: ShoppingListEntry[] = [];
  let cancelled = false;

  async function connect() {
    if (cancelled) return;
    try {
      const records = await pb.collection('shopping_list').getFullList({
        filter: `household = "${householdId}"`,
        sort: 'created',
      });
      current = records.map(mapShoppingRecord);
      onChange(current);

      await pb.collection('shopping_list').subscribe('*', (e) => {
        if ((e.record as any).household !== householdId) return;
        if (e.action === 'create') {
          current = [...current, mapShoppingRecord(e.record)];
        } else if (e.action === 'update') {
          current = current.map((i) => (i.id === e.record.id ? mapShoppingRecord(e.record) : i));
        } else if (e.action === 'delete') {
          current = current.filter((i) => i.id !== e.record.id);
        }
        onChange(current);
      });
    } catch {
      if (!cancelled) setTimeout(connect, 5000);
    }
  }

  connect();
  return () => {
    cancelled = true;
    pb.collection('shopping_list').unsubscribe('*');
  };
}
