/// Typed-item list view — toolbar (search, new, sync, lock, settings) +
/// type-iconed rows. Clicking a row fetches the full Item and navigates
/// to the detail view.

import { getState, setState, sendMessage, navigate, escapeHtml, openVaultTab } from '../../shared/state';
import { showToast } from '../../shared/toast';
import {
  GLYPH_VAULT_TAB,
  GLYPH_DEVICES, GLYPH_LOCK,
  GLYPH_TYPE_LOGIN, GLYPH_TYPE_SECURE_NOTE, GLYPH_TYPE_TOTP,
  GLYPH_TYPE_CARD, GLYPH_TYPE_IDENTITY, GLYPH_TYPE_KEY, GLYPH_TYPE_DOCUMENT,
} from '../../shared/glyphs';
import type { ItemId, ItemType, ManifestEntry, Item } from '../../shared/types';

/// Extract the display hostname from an icon_hint or fallback to the first tag.
function metaLine(e: ManifestEntry): string {
  if (e.icon_hint) return e.icon_hint;
  if (e.tags.length > 0) return e.tags.join(', ');
  return '';
}

/// Glyph icon per item type.
function typeIcon(t: ItemType): string {
  switch (t) {
    case 'login':       return GLYPH_TYPE_LOGIN;
    case 'secure_note': return GLYPH_TYPE_SECURE_NOTE;
    case 'identity':    return GLYPH_TYPE_IDENTITY;
    case 'card':        return GLYPH_TYPE_CARD;
    case 'key':         return GLYPH_TYPE_KEY;
    case 'document':    return GLYPH_TYPE_DOCUMENT;
    case 'totp':        return GLYPH_TYPE_TOTP;
  }
}

function buildRowsHtml(): string {
  const state = getState();
  const filtered = getFilteredEntries();
  if (filtered.length > 0) {
    return filtered.map(([id, e], i) => `
        <div class="entry-row ${i === state.selectedIndex ? 'selected' : ''}" data-id="${escapeHtml(id)}" data-index="${i}">
          <span class="entry-name"><span class="type-icon" aria-hidden="true">${typeIcon(e.type)}</span> ${escapeHtml(e.title)}${e.attachment_summaries.length > 0 ? ' <span class="entry-row__attach-indicator" title="has attachments">⊕</span>' : ''}</span>
          <span class="entry-meta">${escapeHtml(metaLine(e))}</span>
        </div>
      `).join('');
  }
  if (state.searchQuery) {
    return `
      <div class="empty-state">
        <span class="empty-state__icon" aria-hidden="true">⊘</span>
        <div class="empty-state__title">No results for "${escapeHtml(state.searchQuery)}"</div>
        <div class="empty-state__hint">Try a shorter search term.</div>
      </div>
    `;
  }
  return `
    <div class="empty-state">
      <span class="empty-state__icon" aria-hidden="true">◈</span>
      <div class="empty-state__title">No items yet</div>
      <div class="empty-state__hint">Press <kbd>+</kbd> to add your first item.</div>
    </div>
  `;
}

function updateItemList(): void {
  const list = document.getElementById('item-list');
  if (list) {
    list.innerHTML = buildRowsHtml();
    wireRowClicks();
  }
}

function wireRowClicks(): void {
  document.querySelectorAll('.entry-row').forEach(row => {
    row.addEventListener('click', async () => {
      const id = (row as HTMLElement).dataset.id!;
      document.removeEventListener('keydown', handleListKeydown);
      await openItem(id);
    });
  });
}

export function renderItemList(app: HTMLElement): void {
  const state = getState();
  app.innerHTML = `
    <div class="search-bar">
      <input type="text" id="search-input" placeholder="/ search..." value="${escapeHtml(state.searchQuery)}">
    </div>
    <div class="toolbar" style="display:flex; gap:4px; padding:6px 12px; border-bottom:1px solid #21262d;">
      <button class="btn" id="new-btn" style="font-size:11px;">+ new</button>
      <button class="btn" id="sync-btn" style="font-size:11px;">sync</button>
      <span style="flex:1;"></span>
      <button class="btn" id="vault-btn" style="font-size:11px;" title="Open vault (Shift+F)">${GLYPH_VAULT_TAB}</button>
      <button class="btn" id="settings-btn" style="font-size:11px;">settings</button>
      <button class="btn" id="lock-btn" style="font-size:11px;">lock</button>
    </div>
    <div class="entry-list" id="item-list">
      ${buildRowsHtml()}
    </div>
    <div class="keyhints">
      <span><kbd>/</kbd> search</span>
      <span><kbd>+</kbd> new</span>
      <span><kbd>&uarr;&darr;</kbd> nav</span>
      <span><kbd>Enter</kbd> open</span>
    </div>
  `;

  // --- Event listeners ---

  const searchInput = document.getElementById('search-input') as HTMLInputElement | null;
  searchInput?.addEventListener('input', () => {
    const state2 = getState();
    state2.searchQuery = searchInput.value;
    state2.selectedIndex = 0;
    const list = document.getElementById('item-list');
    if (list) list.innerHTML = buildRowsHtml();
    wireRowClicks();
  });

  document.getElementById('vault-btn')?.addEventListener('click', () => openVaultTab());

  document.getElementById('new-btn')?.addEventListener('click', () => {
    setState({ newType: null });
    navigate('add');
  });

  document.getElementById('sync-btn')?.addEventListener('click', async () => {
    setState({ loading: true, error: null });
    const resp = await sendMessage({ type: 'sync' });
    if (resp.ok) {
      const listResp = await sendMessage({ type: 'list_items' });
      if (listResp.ok) {
        const data = listResp.data as { items: Array<[ItemId, ManifestEntry]> };
        setState({ entries: data.items, loading: false });
        showToast('Synced', 'success');
        return;
      }
      setState({ loading: false, error: listResp.error });
      showToast(listResp.error ?? 'Sync failed', 'error');
    } else {
      setState({ loading: false, error: resp.error });
      showToast(resp.error ?? 'Sync failed', 'error');
    }
  });

  document.getElementById('lock-btn')?.addEventListener('click', async () => {
    await sendMessage({ type: 'lock' });
    navigate('locked');
  });

  document.getElementById('settings-btn')?.addEventListener('click', (e) => {
    e.stopPropagation();
    showSettingsPicker(e.currentTarget as HTMLElement);
  });

  wireRowClicks();

  document.addEventListener('keydown', handleListKeydown);
}

async function openItem(id: ItemId): Promise<void> {
  setState({ loading: true });
  const resp = await sendMessage({ type: 'get_item', id });
  if (resp.ok) {
    const data = resp.data as { item: Item };
    navigate('detail', {
      selectedId: id,
      selectedItem: data.item,
    });
  } else {
    setState({ loading: false, error: resp.error });
  }
}

/// Compute the visible (filtered) entry list from current state.
function getFilteredEntries(): Array<[ItemId, ManifestEntry]> {
  const state = getState();
  const entries: Array<[ItemId, ManifestEntry]> = state.entries;
  // Hide trashed items from the main list.
  let filtered = entries.filter(([, e]) => e.trashed_at === undefined || e.trashed_at === null);
  if (state.searchQuery) {
    const q = state.searchQuery.toLowerCase();
    filtered = filtered.filter(([, e]) => {
      if (e.title.toLowerCase().includes(q)) return true;
      if (e.icon_hint?.toLowerCase().includes(q)) return true;
      if (e.group?.toLowerCase().includes(q)) return true;
      if (e.tags.some((t) => t.toLowerCase().includes(q))) return true;
      return false;
    });
  }
  filtered.sort((a, b) => a[1].title.localeCompare(b[1].title));
  return filtered;
}

/// True if the event target is an editable field (input/textarea/contenteditable).
/// Global shortcut handlers should bail when the user is typing into a field —
/// otherwise printable characters like "/" and "+" get eaten by the shortcut
/// routing and never reach the input.
function isEditableTarget(target: EventTarget | null): boolean {
  if (!(target instanceof HTMLElement)) return false;
  const tag = target.tagName;
  if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;
  if (target.isContentEditable) return true;
  return false;
}

function handleListKeydown(e: KeyboardEvent): void {
  const state = getState();
  const target = e.target as HTMLElement;
  const isSearch = target.id === 'search-input';

  // If the user is typing into any input/textarea (other than the list's own
  // search field, which we want to focus on "/" even from outside it), let the
  // keystroke through. The "/" shortcut below is specifically "jump to search
  // from the list," not "steal printable characters while typing."
  if (isEditableTarget(target) && !isSearch) {
    if (e.key === 'Escape') {
      document.removeEventListener('keydown', handleListKeydown);
      window.close();
    }
    return;
  }

  if (e.key === '/' && !isSearch) {
    e.preventDefault();
    (document.getElementById('search-input') as HTMLInputElement | null)?.focus();
    return;
  }

  if (e.key === '+' && !isSearch) {
    e.preventDefault();
    document.removeEventListener('keydown', handleListKeydown);
    navigate('add');
    return;
  }

  if (e.key === 'F' && e.shiftKey) {
    e.preventDefault();
    openVaultTab();
    return;
  }

  const filtered = getFilteredEntries();

  if (e.key === 'ArrowDown') {
    e.preventDefault();
    const max = Math.max(filtered.length - 1, 0);
    state.selectedIndex = Math.min(state.selectedIndex + 1, max);
    updateItemList();
    return;
  }

  if (e.key === 'ArrowUp') {
    e.preventDefault();
    state.selectedIndex = Math.max(state.selectedIndex - 1, 0);
    updateItemList();
    return;
  }

  if (e.key === 'Enter') {
    e.preventDefault();
    const selected = filtered[state.selectedIndex];
    if (selected) {
      document.removeEventListener('keydown', handleListKeydown);
      void openItem(selected[0]);
    }
    return;
  }

  if (e.key === 'Escape') {
    document.removeEventListener('keydown', handleListKeydown);
    window.close();
    return;
  }
}

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Settings picker popover (device vs vault)
// ----------------------------------------------------------------------

const SETTINGS_OPTIONS: Array<{ view: 'settings' | 'settings-vault'; icon: string; label: string }> = [
  { view: 'settings',       icon: GLYPH_DEVICES,  label: 'device settings' },
  { view: 'settings-vault', icon: GLYPH_LOCK,  label: 'vault settings' },
];

function showSettingsPicker(anchor: HTMLElement): void {
  document.querySelectorAll('.settings-picker').forEach((el) => el.remove());

  const picker = document.createElement('div');
  picker.className = 'settings-picker';
  Object.assign(picker.style, {
    position: 'absolute',
    background: '#161b22',
    border: '1px solid #30363d',
    borderRadius: '6px',
    boxShadow: '0 4px 12px rgba(0,0,0,0.4)',
    padding: '4px',
    minWidth: '170px',
    zIndex: '999999',
    fontSize: '12px',
  });

  const rect = anchor.getBoundingClientRect();
  picker.style.top = `${rect.bottom + 4}px`;
  picker.style.left = `${rect.left}px`;

  for (const opt of SETTINGS_OPTIONS) {
    const row = document.createElement('div');
    Object.assign(row.style, {
      padding: '6px 10px', cursor: 'pointer', color: '#c9d1d9',
      borderRadius: '4px', display: 'flex', alignItems: 'center', gap: '8px',
    });
    const iconSpan = document.createElement('span');
    iconSpan.textContent = opt.icon;
    Object.assign(iconSpan.style, { fontSize: '14px', width: '16px', textAlign: 'center' });
    const labelSpan = document.createElement('span');
    labelSpan.textContent = opt.label;
    row.appendChild(iconSpan);
    row.appendChild(labelSpan);
    row.addEventListener('mouseenter', () => { row.style.background = '#21262d'; });
    row.addEventListener('mouseleave', () => { row.style.background = 'transparent'; });
    row.addEventListener('click', (ev) => {
      ev.stopPropagation();
      picker.remove();
      document.removeEventListener('click', closeOnOutside);
      document.removeEventListener('keydown', closeOnEsc);
      navigate(opt.view);
    });
    picker.appendChild(row);
  }

  document.body.appendChild(picker);

  const closeOnOutside = (ev: MouseEvent) => {
    if (!picker.contains(ev.target as Node)) {
      picker.remove();
      document.removeEventListener('click', closeOnOutside);
      document.removeEventListener('keydown', closeOnEsc);
    }
  };
  const closeOnEsc = (ev: KeyboardEvent) => {
    if (ev.key === 'Escape') {
      picker.remove();
      document.removeEventListener('click', closeOnOutside);
      document.removeEventListener('keydown', closeOnEsc);
    }
  };
  setTimeout(() => {
    document.addEventListener('click', closeOnOutside);
    document.addEventListener('keydown', closeOnEsc);
  }, 0);
}
