import { Platform } from 'react-native';
import { RecordModel } from 'pocketbase';
import { pb } from './pocketbase';
import { syncQueue, isOfflineError } from '../lib/syncQueue';
import { getPhotoUrl, buildPhotoFormData, compressPhoto } from './storage';
import { HouseholdItem } from '../types';

type CreateItemInput = Omit<HouseholdItem, 'id' | 'createdAt' | 'updatedAt' | 'onShoppingList'> & {
  photoUri?: string;
};

function mapItemRecord(r: RecordModel): HouseholdItem {
  return {
    id: r.id,
    name: r.name,
    description: r.description ?? '',
    category: r.category,
    quantity: r.quantity ?? 0,
    unit: r.unit,
    minStockThreshold: r.min_stock_threshold ?? 0,
    onShoppingList: r.on_shopping_list ?? false,
    photoUrl: getPhotoUrl(r),
    storageLocation: r.storage_location ?? '',
    shoppingLocation: r.shopping_location ?? '',
    price: r.price ?? null,
    expiryDate: r.expiry_date ? new Date(r.expiry_date) : null,
    barcode: r.barcode ?? null,
    addedByDevice: r.added_by_device ?? '',
    createdAt: new Date(r.created),
    updatedAt: new Date(r.updated),
  };
}

function getStore() {
  // Lazy import to avoid circular dependency
  const { useHouseholdStore } = require('../hooks/useHousehold');
  return useHouseholdStore.getState();
}

export async function createItem(householdId: string, input: CreateItemInput): Promise<HouseholdItem> {
  const { photoUri, ...itemData } = input;

  const buildData = () => ({
    household: householdId,
    name: itemData.name,
    description: itemData.description,
    category: itemData.category,
    quantity: itemData.quantity,
    unit: itemData.unit,
    min_stock_threshold: itemData.minStockThreshold,
    on_shopping_list: false,
    storage_location: itemData.storageLocation,
    shopping_location: itemData.shoppingLocation,
    price: itemData.price ?? null,
    expiry_date: itemData.expiryDate?.toISOString() ?? null,
    barcode: itemData.barcode ?? null,
    added_by_device: itemData.addedByDevice,
  });

  try {
    let record: RecordModel;
    if (photoUri) {
      const compressed = await compressPhoto(photoUri);
      const fd = await buildPhotoFormData('photo', compressed);
      const plain = buildData();
      Object.entries(plain).forEach(([k, v]) => {
        if (v != null) fd.append(k, String(v));
      });
      record = await pb.collection('items').create(fd);
    } else {
      record = await pb.collection('items').create(buildData());
    }
    return mapItemRecord(record);
  } catch (e) {
    if (isOfflineError(e)) {
      const optimistic: HouseholdItem = {
        ...itemData,
        id: 'offline_' + Date.now(),
        onShoppingList: false,
        photoUrl: null,
        createdAt: new Date(),
        updatedAt: new Date(),
      };
      const store = getStore();
      store.setItems([...store.items, optimistic]);
      await syncQueue.add({
        type: 'createItem',
        payload: { householdId, input: { ...itemData } },
      });
      return optimistic;
    }
    throw e;
  }
}

export async function updateItemQuantity(
  householdId: string,
  itemId: string,
  newQuantity: number
): Promise<void> {
  const store = getStore();
  store.setItems(
    store.items.map((i: HouseholdItem) => (i.id === itemId ? { ...i, quantity: newQuantity } : i))
  );
  try {
    // Server-hook handles shopping list auto-add/remove
    await pb.collection('items').update(itemId, { quantity: newQuantity });
  } catch (e) {
    if (isOfflineError(e)) {
      await syncQueue.add({ type: 'updateItemQuantity', payload: { householdId, itemId, qty: newQuantity } });
    } else throw e;
  }
}

export async function updateItem(
  householdId: string,
  itemId: string,
  changes: Partial<HouseholdItem> & { photoUri?: string }
): Promise<void> {
  const { photoUri, photoUrl: _photoUrl, ...rest } = changes as any;

  const plain: Record<string, unknown> = {
    ...(rest.name !== undefined && { name: rest.name }),
    ...(rest.description !== undefined && { description: rest.description }),
    ...(rest.storageLocation !== undefined && { storage_location: rest.storageLocation }),
    ...(rest.shoppingLocation !== undefined && { shopping_location: rest.shoppingLocation }),
    ...(rest.price !== undefined && { price: rest.price }),
    ...(rest.minStockThreshold !== undefined && { min_stock_threshold: rest.minStockThreshold }),
    ...(rest.expiryDate !== undefined && { expiry_date: rest.expiryDate?.toISOString() ?? null }),
    ...(rest.barcode !== undefined && { barcode: rest.barcode }),
  };

  const store = getStore();
  store.setItems(
    store.items.map((i: HouseholdItem) =>
      i.id === itemId ? { ...i, ...changes, updatedAt: new Date() } : i
    )
  );

  try {
    if (photoUri) {
      const compressed = await compressPhoto(photoUri);
      const fd = await buildPhotoFormData('photo', compressed);
      Object.entries(plain).forEach(([k, v]) => {
        if (v != null) fd.append(k, String(v));
      });
      await pb.collection('items').update(itemId, fd);
    } else {
      await pb.collection('items').update(itemId, plain);
    }
  } catch (e) {
    if (isOfflineError(e)) {
      await syncQueue.add({ type: 'updateItem', payload: { householdId, itemId, changes: plain } });
    } else throw e;
  }
}

export async function deleteItem(householdId: string, itemId: string): Promise<void> {
  const store = getStore();
  store.setItems(store.items.filter((i: HouseholdItem) => i.id !== itemId));

  try {
    const orphans = await pb.collection('shopping_list').getFullList({
      filter: `item_id = "${itemId}"`,
    });
    await Promise.all(orphans.map((e) => pb.collection('shopping_list').delete(e.id)));
    await pb.collection('items').delete(itemId);
  } catch (e) {
    if (isOfflineError(e)) {
      await syncQueue.add({ type: 'deleteItem', payload: { householdId, itemId } });
    } else throw e;
  }
}

export function subscribeToItems(
  householdId: string,
  onChange: (items: HouseholdItem[]) => void
): () => void {
  let current: HouseholdItem[] = [];
  let cancelled = false;

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

      await pb.collection('items').subscribe('*', (e) => {
        if ((e.record as any).household !== householdId) return;
        if (e.action === 'create') {
          current = [...current, mapItemRecord(e.record)].sort((a, b) =>
            a.name.localeCompare(b.name, 'de')
          );
        } else if (e.action === 'update') {
          current = current.map((i) => (i.id === e.record.id ? mapItemRecord(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('items').unsubscribe('*');
  };
}
