<template>
  <main class="container page-padding">
    <div v-if="loading" class="text-center">
      <div class="spinner-dots" role="status"><span /><span /><span /></div>
      <p>Loading list details...</p>
    </div>

    <div v-else-if="error" class="alert alert-error mb-3" role="alert">
      <div class="alert-content">
        <svg class="icon" aria-hidden="true">
          <use xlink:href="#icon-alert-triangle" />
        </svg>
        {{ error }}
      </div>
      <button type="button" class="btn btn-sm btn-danger" @click="fetchListDetails">Retry</button>
    </div>

    <template v-else-if="list">
      <div class="flex justify-between items-center flex-wrap mb-2">
        <h1>{{ list.name }}</h1>
        <div class="flex items-center flex-wrap" style="gap: 0.5rem;">
          <button class="btn btn-neutral btn-sm" @click="showCostSummaryDialog = true"
            :class="{ 'feature-offline-disabled': !isOnline }"
            :data-tooltip="!isOnline ? 'Cost summary requires online connection' : ''">
            <svg class="icon icon-sm">
              <use xlink:href="#icon-clipboard" />
            </svg>
            Cost Summary
          </button>
          <button class="btn btn-secondary btn-sm" @click="openOcrDialog"
            :class="{ 'feature-offline-disabled': !isOnline }"
            :data-tooltip="!isOnline ? 'OCR requires online connection' : ''">
            <svg class="icon icon-sm">
              <use xlink:href="#icon-plus" />
            </svg>
            Add via OCR
          </button>
          <span class="item-badge ml-1" :class="list.is_complete ? 'badge-settled' : 'badge-pending'">
            {{ list.is_complete ? 'Complete' : 'Active' }}
          </span>
        </div>
      </div>

      <!-- Add Item Form -->
      <form @submit.prevent="onAddItem" class="card mb-3">
        <div class="card-body">
          <div class="flex items-end flex-wrap" style="gap: 1rem;">
            <div class="form-group flex-grow" style="margin-bottom: 0;">
              <label for="newItemName" class="form-label">Item Name</label>
              <input type="text" id="newItemName" v-model="newItem.name" class="form-input" required
                ref="itemNameInputRef" />
            </div>
            <div class="form-group" style="margin-bottom: 0; min-width: 120px;">
              <label for="newItemQuantity" class="form-label">Quantity</label>
              <input type="number" id="newItemQuantity" v-model="newItem.quantity" class="form-input" min="1" />
            </div>
            <button type="submit" class="btn btn-primary" :disabled="addingItem">
              <span v-if="addingItem" class="spinner-dots-sm" role="status"><span /><span /><span /></span>
              Add Item
            </button>
          </div>
        </div>
      </form>

      <!-- Items List -->
      <div v-if="list.items.length === 0" class="card empty-state-card">
        <svg class="icon icon-lg" aria-hidden="true">
          <use xlink:href="#icon-clipboard" />
        </svg>
        <h3>No Items Yet!</h3>
        <p>This list is empty. Add some items using the form above.</p>
      </div>

      <ul v-else class="item-list">
        <li v-for="item in list.items" :key="item.id" class="list-item" :class="{
          'completed': item.is_complete,
          'is-swiped': item.swiped,
          'offline-item': isItemPendingSync(item),
          'synced': !isItemPendingSync(item)
        }" @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd">
          <div class="list-item-content">
            <div class="list-item-main">
              <label class="checkbox-label mb-0 flex-shrink-0">
                <input type="checkbox" :checked="item.is_complete"
                  @change="confirmUpdateItem(item, ($event.target as HTMLInputElement).checked)"
                  :disabled="item.updating" :aria-label="item.name" />
                <span class="checkmark"></span>
              </label>
              <div class="item-text flex-grow">
                <span :class="{ 'text-decoration-line-through': item.is_complete }">{{ item.name }}</span>
                <small v-if="item.quantity" class="item-caption">Quantity: {{ item.quantity }}</small>
                <div v-if="item.is_complete" class="form-group mt-1" style="max-width: 150px; margin-bottom: 0;">
                  <label :for="`price-${item.id}`" class="sr-only">Price for {{ item.name }}</label>
                  <input :id="`price-${item.id}`" type="number" v-model.number="item.priceInput"
                    class="form-input form-input-sm" placeholder="Price" step="0.01" @blur="updateItemPrice(item)"
                    @keydown.enter.prevent="($event.target as HTMLInputElement).blur()" />
                </div>
              </div>
            </div>
            <div class="list-item-actions">
              <button class="btn btn-danger btn-sm btn-icon-only" @click.stop="confirmDeleteItem(item)"
                :disabled="item.deleting" aria-label="Delete item">
                <svg class="icon icon-sm">
                  <use xlink:href="#icon-trash"></use>
                </svg>
              </button>
            </div>
          </div>
        </li>
      </ul>
    </template>

    <!-- OCR Dialog -->
    <div v-if="showOcrDialogState" class="modal-backdrop open" @click.self="closeOcrDialog">
      <div class="modal-container" ref="ocrModalRef" style="min-width: 400px;">
        <div class="modal-header">
          <h3>Add Items via OCR</h3>
          <button class="close-button" @click="closeOcrDialog" aria-label="Close"><svg class="icon">
              <use xlink:href="#icon-close" />
            </svg></button>
        </div>
        <div class="modal-body">
          <div v-if="ocrLoading" class="text-center">
            <div class="spinner-dots"><span /><span /><span /></div>
            <p>Processing image...</p>
          </div>
          <div v-else-if="ocrItems.length > 0">
            <p class="mb-2">Review Extracted Items:</p>
            <ul class="item-list">
              <li v-for="(ocrItem, index) in ocrItems" :key="index" class="list-item">
                <div class="list-item-content flex items-center" style="gap: 0.5rem;">
                  <input type="text" v-model="ocrItem.name" class="form-input flex-grow" required />
                  <button class="btn btn-danger btn-sm btn-icon-only" @click="ocrItems.splice(index, 1)">
                    <svg class="icon icon-sm">
                      <use xlink:href="#icon-trash" />
                    </svg>
                  </button>
                </div>
              </li>
            </ul>
          </div>
          <div v-else class="form-group">
            <label for="ocrFile" class="form-label">Upload Image</label>
            <input type="file" id="ocrFile" class="form-input" accept="image/*" @change="handleOcrFileUpload"
              ref="ocrFileInputRef" />
            <p v-if="ocrError" class="form-error-text mt-1">{{ ocrError }}</p>
          </div>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-neutral" @click="closeOcrDialog">Cancel</button>
          <button v-if="ocrItems.length > 0" type="button" class="btn btn-primary ml-2" @click="addOcrItems"
            :disabled="addingOcrItems">
            <span v-if="addingOcrItems" class="spinner-dots-sm"><span /><span /><span /></span>
            Add Items
          </button>
        </div>
      </div>
    </div>

    <!-- Confirmation Dialog -->
    <div v-if="showConfirmDialogState" class="modal-backdrop open" @click.self="cancelConfirmation">
      <div class="modal-container confirm-modal" ref="confirmModalRef">
        <div class="modal-header">
          <h3>Confirmation</h3>
          <button class="close-button" @click="cancelConfirmation" aria-label="Close"><svg class="icon">
              <use xlink:href="#icon-close" />
            </svg></button>
        </div>
        <div class="modal-body">
          <svg class="icon icon-lg mb-2" style="color: var(--warning);">
            <use xlink:href="#icon-alert-triangle" />
          </svg>
          <p>{{ confirmDialogMessage }}</p>
        </div>
        <div class="modal-footer">
          <button class="btn btn-neutral" @click="cancelConfirmation">Cancel</button>
          <button class="btn btn-primary ml-2" @click="handleConfirmedAction">Confirm</button>
        </div>
      </div>
    </div>

    <!-- Cost Summary Dialog -->
    <div v-if="showCostSummaryDialog" class="modal-backdrop open" @click.self="showCostSummaryDialog = false">
      <div class="modal-container" ref="costSummaryModalRef" style="min-width: 550px;">
        <div class="modal-header">
          <h3>List Cost Summary</h3>
          <button class="close-button" @click="showCostSummaryDialog = false" aria-label="Close"><svg class="icon">
              <use xlink:href="#icon-close" />
            </svg></button>
        </div>
        <div class="modal-body">
          <div v-if="costSummaryLoading" class="text-center">
            <div class="spinner-dots"><span /><span /><span /></div>
            <p>Loading summary...</p>
          </div>
          <div v-else-if="costSummaryError" class="alert alert-error">{{ costSummaryError }}</div>
          <div v-else-if="listCostSummary">
            <div class="mb-3 cost-overview">
              <p><strong>Total List Cost:</strong> {{ formatCurrency(listCostSummary.total_list_cost) }}</p>
              <p><strong>Equal Share Per User:</strong> {{ formatCurrency(listCostSummary.equal_share_per_user) }}</p>
              <p><strong>Participating Users:</strong> {{ listCostSummary.num_participating_users }}</p>
            </div>
            <h4>User Balances</h4>
            <div class="table-container mt-2">
              <table class="table">
                <thead>
                  <tr>
                    <th>User</th>
                    <th class="text-right">Items Added Value</th>
                    <th class="text-right">Amount Due</th>
                    <th class="text-right">Balance</th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="userShare in listCostSummary.user_balances" :key="userShare.user_id">
                    <td>{{ userShare.user_identifier }}</td>
                    <td class="text-right">{{ formatCurrency(userShare.items_added_value) }}</td>
                    <td class="text-right">{{ formatCurrency(userShare.amount_due) }}</td>
                    <td class="text-right">
                      <span class="item-badge"
                        :class="parseFloat(String(userShare.balance)) >= 0 ? 'badge-settled' : 'badge-pending'">
                        {{ formatCurrency(userShare.balance) }}
                      </span>
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
          <p v-else>No cost summary available.</p>
        </div>
        <div class="modal-footer">
          <button type="button" class="btn btn-primary" @click="showCostSummaryDialog = false">Close</button>
        </div>
      </div>
    </div>

  </main>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue';
import { useRoute } from 'vue-router';
import { apiClient, API_ENDPOINTS } from '@/config/api';
import { onClickOutside, useEventListener, useFileDialog, useNetwork } from '@vueuse/core';
import { useNotificationStore } from '@/stores/notifications';
import { useOfflineStore, type CreateListItemPayload } from '@/stores/offline';

interface Item {
  id: number;
  name: string;
  quantity?: string | undefined | number; // Allow number for input binding
  is_complete: boolean;
  price?: number | null;
  version: number;
  updating?: boolean;
  updated_at: string;
  deleting?: boolean;
  // For UI state
  priceInput?: string | number | null; // Separate for input binding due to potential nulls/strings
  swiped?: boolean; // For swipe UI
}

interface List {
  id: number;
  name: string;
  description?: string;
  is_complete: boolean;
  items: Item[];
  version: number;
  updated_at: string;
}

interface UserCostShare {
  user_id: number;
  user_identifier: string;
  items_added_value: string | number;
  amount_due: string | number;
  balance: string | number;
}

interface ListCostSummaryData {
  list_id: number;
  list_name: string;
  total_list_cost: string | number;
  num_participating_users: number;
  equal_share_per_user: string | number;
  user_balances: UserCostShare[];
}

const route = useRoute();
const { isOnline } = useNetwork();
const notificationStore = useNotificationStore();
const offlineStore = useOfflineStore();
const list = ref<List | null>(null);
const loading = ref(true);
const error = ref<string | null>(null);
const addingItem = ref(false);
const pollingInterval = ref<ReturnType<typeof setInterval> | null>(null);
const lastListUpdate = ref<string | null>(null);
const lastItemUpdate = ref<string | null>(null);

const newItem = ref<{ name: string; quantity?: string | number }>({ name: '' });
const itemNameInputRef = ref<HTMLInputElement | null>(null);

// OCR
const showOcrDialogState = ref(false);
const ocrModalRef = ref<HTMLElement | null>(null);
const ocrLoading = ref(false);
const ocrItems = ref<{ name: string }[]>([]); // Items extracted from OCR
const addingOcrItems = ref(false);
const ocrError = ref<string | null>(null);
const ocrFileInputRef = ref<HTMLInputElement | null>(null);
const { files: ocrFiles, reset: resetOcrFileDialog } = useFileDialog({
  accept: 'image/*',
  multiple: false,
});


// Confirmation Dialog
const showConfirmDialogState = ref(false);
const confirmModalRef = ref<HTMLElement | null>(null);
const confirmDialogMessage = ref('');
const pendingAction = ref<(() => Promise<void>) | null>(null);

// Cost Summary
const showCostSummaryDialog = ref(false);
const costSummaryModalRef = ref<HTMLElement | null>(null);
const listCostSummary = ref<ListCostSummaryData | null>(null);
const costSummaryLoading = ref(false);
const costSummaryError = ref<string | null>(null);


onClickOutside(ocrModalRef, () => { showOcrDialogState.value = false; });
onClickOutside(costSummaryModalRef, () => { showCostSummaryDialog.value = false; });
onClickOutside(confirmModalRef, () => { showConfirmDialogState.value = false; pendingAction.value = null; });


const formatCurrency = (value: string | number | undefined | null): string => {
  if (value === undefined || value === null) return '$0.00';
  const numValue = typeof value === 'string' ? parseFloat(value) : value;
  return isNaN(numValue) ? '$0.00' : `$${numValue.toFixed(2)}`;
};

const processListItems = (items: Item[]): Item[] => {
  return items.map(item => ({
    ...item,
    priceInput: item.price !== null && item.price !== undefined ? item.price : ''
  }));
};

const fetchListDetails = async () => {
  loading.value = true;
  error.value = null;
  try {
    const response = await apiClient.get(API_ENDPOINTS.LISTS.BY_ID(String(route.params.id)));
    const rawList = response.data as List;
    rawList.items = processListItems(rawList.items);
    list.value = rawList;

    lastListUpdate.value = rawList.updated_at;
    lastItemUpdate.value = rawList.items.reduce((latest: string, item: Item) => {
      return item.updated_at > latest ? item.updated_at : latest;
    }, '');

    if (showCostSummaryDialog.value) { // If dialog is open, refresh its data
      await fetchListCostSummary();
    }

  } catch (err: unknown) {
    error.value = (err instanceof Error ? err.message : String(err)) || 'Failed to load list details.';
  } finally {
    loading.value = false;
  }
};

const checkForUpdates = async () => {
  if (!list.value) return;
  try {
    const response = await apiClient.get(API_ENDPOINTS.LISTS.BY_ID(String(list.value.id)));
    const { updated_at: newListUpdatedAt, items: newItems } = response.data as List;
    const newLastItemUpdate = newItems.reduce((latest: string, item: Item) => item.updated_at > latest ? item.updated_at : latest, '');

    if ((lastListUpdate.value && newListUpdatedAt > lastListUpdate.value) ||
      (lastItemUpdate.value && newLastItemUpdate > lastItemUpdate.value)) {
      await fetchListDetails();
    }
  } catch (err) {
    console.warn('Polling for updates failed:', err);
  }
};

const startPolling = () => {
  stopPolling();
  pollingInterval.value = setInterval(() => checkForUpdates(), 15000);
};
const stopPolling = () => {
  if (pollingInterval.value) clearInterval(pollingInterval.value);
};

const isItemPendingSync = (item: Item) => {
  return offlineStore.pendingActions.some(action => {
    if (action.type === 'update_list_item' || action.type === 'delete_list_item') {
      const payload = action.payload as { listId: string; itemId: string };
      return payload.itemId === String(item.id);
    }
    return false;
  });
};

const onAddItem = async () => {
  if (!list.value || !newItem.value.name.trim()) {
    notificationStore.addNotification({ message: 'Please enter an item name.', type: 'warning' });
    itemNameInputRef.value?.focus();
    return;
  }
  addingItem.value = true;

  if (!isOnline.value) {
    // Add to offline queue
    offlineStore.addAction({
      type: 'create_list_item',
      payload: {
        listId: String(list.value.id),
        itemData: {
          name: newItem.value.name,
          quantity: newItem.value.quantity?.toString()
        }
      }
    });
    // Optimistically add to UI
    const optimisticItem: Item = {
      id: Date.now(), // Temporary ID
      name: newItem.value.name,
      quantity: newItem.value.quantity,
      is_complete: false,
      version: 1,
      updated_at: new Date().toISOString()
    };
    list.value.items.push(processListItems([optimisticItem])[0]);
    newItem.value = { name: '' };
    itemNameInputRef.value?.focus();
    addingItem.value = false;
    return;
  }

  try {
    const response = await apiClient.post(
      API_ENDPOINTS.LISTS.ITEMS(String(list.value.id)),
      { name: newItem.value.name, quantity: newItem.value.quantity?.toString() }
    );
    const addedItem = response.data as Item;
    list.value.items.push(processListItems([addedItem])[0]);
    newItem.value = { name: '' };
    itemNameInputRef.value?.focus();
  } catch (err) {
    notificationStore.addNotification({ message: (err instanceof Error ? err.message : String(err)) || 'Failed to add item.', type: 'error' });
  } finally {
    addingItem.value = false;
  }
};

const updateItem = async (item: Item, newCompleteStatus: boolean) => {
  if (!list.value) return;
  item.updating = true;
  const originalCompleteStatus = item.is_complete;
  item.is_complete = newCompleteStatus; // Optimistic update

  if (!isOnline.value) {
    // Add to offline queue
    offlineStore.addAction({
      type: 'update_list_item',
      payload: {
        listId: String(list.value.id),
        itemId: String(item.id),
        data: {
          completed: newCompleteStatus
        },
        version: item.version
      }
    });
    item.updating = false;
    return;
  }

  try {
    await apiClient.put(
      API_ENDPOINTS.LISTS.ITEM(String(list.value.id), String(item.id)),
      { completed: newCompleteStatus, version: item.version }
    );
    item.version++;
  } catch (err) {
    item.is_complete = originalCompleteStatus; // Revert on error
    notificationStore.addNotification({ message: (err instanceof Error ? err.message : String(err)) || 'Failed to update item.', type: 'error' });
  } finally {
    item.updating = false;
  }
};

const updateItemPrice = async (item: Item) => {
  if (!list.value || !item.is_complete) return;

  const newPrice = item.priceInput !== undefined && String(item.priceInput).trim() !== '' ? parseFloat(String(item.priceInput)) : null;
  if (item.price === newPrice) return;

  item.updating = true;
  const originalPrice = item.price;
  const originalPriceInput = item.priceInput;

  item.price = newPrice;

  if (!isOnline.value) {
    // Add to offline queue
    offlineStore.addAction({
      type: 'update_list_item',
      payload: {
        listId: String(list.value.id),
        itemId: String(item.id),
        data: {
          price: newPrice,
          completed: item.is_complete
        },
        version: item.version
      }
    });
    item.updating = false;
    return;
  }

  try {
    await apiClient.put(
      API_ENDPOINTS.LISTS.ITEM(String(list.value.id), String(item.id)),
      { price: newPrice, completed: item.is_complete, version: item.version }
    );
    item.version++;
  } catch (err) {
    item.price = originalPrice;
    item.priceInput = originalPriceInput;
    notificationStore.addNotification({ message: (err instanceof Error ? err.message : String(err)) || 'Failed to update item price.', type: 'error' });
  } finally {
    item.updating = false;
  }
};

const deleteItem = async (item: Item) => {
  if (!list.value) return;
  item.deleting = true;

  if (!isOnline.value) {
    // Add to offline queue
    offlineStore.addAction({
      type: 'delete_list_item',
      payload: {
        listId: String(list.value.id),
        itemId: String(item.id)
      }
    });
    // Optimistically remove from UI
    list.value.items = list.value.items.filter(i => i.id !== item.id);
    item.deleting = false;
    return;
  }

  try {
    await apiClient.delete(API_ENDPOINTS.LISTS.ITEM(String(list.value.id), String(item.id)));
    list.value.items = list.value.items.filter(i => i.id !== item.id);
  } catch (err) {
    notificationStore.addNotification({ message: (err instanceof Error ? err.message : String(err)) || 'Failed to delete item.', type: 'error' });
  } finally {
    item.deleting = false;
  }
};

// Confirmation dialog logic
const confirmUpdateItem = (item: Item, newCompleteStatus: boolean) => {
  confirmDialogMessage.value = `Mark "${item.name}" as ${newCompleteStatus ? 'complete' : 'incomplete'}?`;
  pendingAction.value = () => updateItem(item, newCompleteStatus);
  showConfirmDialogState.value = true;
};

const confirmDeleteItem = (item: Item) => {
  confirmDialogMessage.value = `Delete "${item.name}"? This cannot be undone.`;
  pendingAction.value = () => deleteItem(item);
  showConfirmDialogState.value = true;
};

const handleConfirmedAction = async () => {
  if (pendingAction.value) {
    await pendingAction.value();
  }
  cancelConfirmation();
};
const cancelConfirmation = () => {
  showConfirmDialogState.value = false;
  pendingAction.value = null;
};


// OCR Functionality
const openOcrDialog = () => {
  ocrItems.value = [];
  ocrError.value = null;
  resetOcrFileDialog(); // Clear previous file selection from useFileDialog
  showOcrDialogState.value = true;
  nextTick(() => {
    if (ocrFileInputRef.value) {
      ocrFileInputRef.value.value = ''; // Manually clear input type=file
    }
  });
};
const closeOcrDialog = () => {
  showOcrDialogState.value = false;
  ocrItems.value = [];
  ocrError.value = null;
};

watch(ocrFiles, async (newFiles) => {
  if (newFiles && newFiles.length > 0) {
    const file = newFiles[0];
    await handleOcrUpload(file);
  }
});

const handleOcrFileUpload = (event: Event) => {
  const target = event.target as HTMLInputElement;
  if (target.files && target.files.length > 0) {
    handleOcrUpload(target.files[0]);
  }
};

const handleOcrUpload = async (file: File) => {
  if (!file) return;
  ocrLoading.value = true;
  ocrError.value = null;
  ocrItems.value = [];
  try {
    const formData = new FormData();
    formData.append('image_file', file);
    const response = await apiClient.post(API_ENDPOINTS.OCR.PROCESS, formData, {
      headers: { 'Content-Type': 'multipart/form-data' }
    });
    ocrItems.value = response.data.extracted_items.map((nameStr: string) => ({ name: nameStr.trim() })).filter((item: { name: string }) => item.name);
    if (ocrItems.value.length === 0) {
      ocrError.value = "No items extracted from the image.";
    }
  } catch (err) {
    ocrError.value = (err instanceof Error ? err.message : String(err)) || 'Failed to process image.';
  } finally {
    ocrLoading.value = false;
    if (ocrFileInputRef.value) ocrFileInputRef.value.value = ''; // Reset file input
  }
};

const addOcrItems = async () => {
  if (!list.value || !ocrItems.value.length) return;
  addingOcrItems.value = true;
  let successCount = 0;
  try {
    for (const item of ocrItems.value) {
      if (!item.name.trim()) continue;
      const response = await apiClient.post(
        API_ENDPOINTS.LISTS.ITEMS(String(list.value.id)),
        { name: item.name, quantity: "1" } // Default quantity
      );
      const addedItem = response.data as Item;
      list.value.items.push(processListItems([addedItem])[0]);
      successCount++;
    }
    if (successCount > 0) notificationStore.addNotification({ message: `${successCount} item(s) added successfully from OCR.`, type: 'success' });
    closeOcrDialog();
  } catch (err) {
    notificationStore.addNotification({ message: (err instanceof Error ? err.message : String(err)) || 'Failed to add OCR items.', type: 'error' });
  } finally {
    addingOcrItems.value = false;
  }
};

// Cost Summary
const fetchListCostSummary = async () => {
  if (!list.value || list.value.id === 0) return;
  costSummaryLoading.value = true;
  costSummaryError.value = null;
  try {
    const response = await apiClient.get(API_ENDPOINTS.COSTS.LIST_SUMMARY(list.value.id));
    listCostSummary.value = response.data;
  } catch (err) {
    costSummaryError.value = (err instanceof Error ? err.message : String(err)) || 'Failed to load cost summary.';
    listCostSummary.value = null;
  } finally {
    costSummaryLoading.value = false;
  }
};
watch(showCostSummaryDialog, (newVal) => {
  if (newVal && (!listCostSummary.value || listCostSummary.value.list_id !== list.value?.id)) {
    fetchListCostSummary();
  }
});


// Keyboard shortcut
useEventListener(window, 'keydown', (event: KeyboardEvent) => {
  if (event.key === 'n' && !event.ctrlKey && !event.metaKey && !event.altKey) {
    // Check if a modal is open or if focus is already in an input/textarea
    const activeElement = document.activeElement;
    if (activeElement && (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA')) {
      return;
    }
    if (showOcrDialogState.value || showCostSummaryDialog.value || showConfirmDialogState.value) {
      return;
    }
    event.preventDefault();
    itemNameInputRef.value?.focus();
  }
});

// Swipe detection (basic)
let touchStartX = 0;
const SWIPE_THRESHOLD = 50; // pixels

const handleTouchStart = (event: TouchEvent) => {
  touchStartX = event.changedTouches[0].clientX;
  // Add class for visual feedback during swipe if desired
};

const handleTouchMove = () => {
  // Can be used for interactive swipe effect
};

const handleTouchEnd = () => {
  // Not implemented: Valerie UI swipe example implies JS adds/removes 'is-swiped'
  // For a simple demo, one might toggle it here based on a more complex gesture
  // This would require more state per item and logic
  // For now, swipe actions are not visually implemented
};


onMounted(() => {
  if (!route.params.id) {
    error.value = 'No list ID provided';
    loading.value = false;
    return;
  }
  fetchListDetails().then(() => {
    startPolling();
  });
});

onUnmounted(() => {
  stopPolling();
});

</script>

<style scoped>
.page-padding {
  padding: 1rem;
}

.mb-1 {
  margin-bottom: 0.5rem;
}

.mb-2 {
  margin-bottom: 1rem;
}

.mb-3 {
  margin-bottom: 1.5rem;
}

.mt-1 {
  margin-top: 0.5rem;
}

.mt-2 {
  margin-top: 1rem;
}

.ml-1 {
  margin-left: 0.25rem;
}

.ml-2 {
  margin-left: 0.5rem;
}

.text-right {
  text-align: right;
}

.flex-grow {
  flex-grow: 1;
}

.item-caption {
  display: block;
  font-size: 0.8rem;
  opacity: 0.6;
  margin-top: 0.25rem;
}

.text-decoration-line-through {
  text-decoration: line-through;
}

.form-input-sm {
  /* For price input */
  padding: 0.4rem 0.6rem;
  font-size: 0.9rem;
}

.cost-overview p {
  margin-bottom: 0.5rem;
  font-size: 1.05rem;
}

.form-error-text {
  color: var(--danger);
  font-size: 0.85rem;
}

.list-item.completed .item-text {
  /* text-decoration: line-through; is handled by span class */
  opacity: 0.7;
}

.list-item-actions {
  margin-left: auto;
  /* Pushes actions to the right */
  padding-left: 1rem;
  /* Space before actions */
}

.offline-item {
  position: relative;
  opacity: 0.8;
  transition: opacity 0.3s ease;
}

.offline-item::after {
  content: '';
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  width: 1rem;
  height: 1rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8'/%3E%3Cpath d='M3 3v5h5'/%3E%3Cpath d='M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16'/%3E%3Cpath d='M16 21h5v-5'/%3E%3C/svg%3E");
  background-size: contain;
  background-repeat: no-repeat;
  animation: spin 1s linear infinite;
}

.offline-item.synced {
  opacity: 1;
}

.offline-item.synced::after {
  display: none;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

.feature-offline-disabled {
  position: relative;
  cursor: not-allowed;
  opacity: 0.6;
}

.feature-offline-disabled::before {
  content: attr(data-tooltip);
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  padding: 0.5rem;
  background-color: var(--bg-color-tooltip, #333);
  color: white;
  border-radius: 0.25rem;
  font-size: 0.875rem;
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  transition: all 0.2s ease;
  z-index: 1000;
}

.feature-offline-disabled:hover::before {
  opacity: 1;
  visibility: visible;
}
</style>