// Shared contract for the vault-tab modules. vault.ts owns the state
// singleton and assembles the VaultController; each vault-* module receives
// it as `ctx`. This module sits at the bottom of the dependency graph —
// it imports only from shared/, never from vault.ts or its sibling modules.

import type { Request, Response } from '../shared/messages';
import type {
  ItemId, ItemType, ManifestEntry, Item, VaultSettings, GeneratorRequest,
} from '../shared/types';
import {
  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';

export type VaultView =
  | 'list' | 'detail' | 'add' | 'edit' | 'trash' | 'devices' | 'settings'
  | 'settings-vault' | 'field-history' | 'history' | 'backup' | 'import';

export interface HashRoute {
  view: VaultView;
  id?: string;
  type?: string;
}

export interface VaultState {
  unlocked: boolean;
  view: VaultView;
  entries: Array<[ItemId, ManifestEntry]>;
  selectedId: ItemId | null;
  selectedItem: Item | null;
  selectedIndex: number;
  searchQuery: string;
  activeGroup: string | null;
  drawerOpen: boolean;
  typePanelOpen: boolean;
  vaultSettings: VaultSettings | null;
  generatorDefaults: GeneratorRequest | null;
  error: string | null;
  loading: boolean;
  newType: ItemType | null;
  capturedTabId: number | null;
  capturedUrl: string;
  historyItemId: ItemId | null;
}

// The controller passed to every vault-* module. vault.ts builds one instance
// and wires each hook to the function that currently lives in vault.ts (later
// Phase-4 tasks repoint individual hooks at the extracted module functions).
export interface VaultController {
  readonly state: VaultState;
  sendMessage(request: Request): Promise<Response>;
  render(): void;
  renderPane(): void;
  renderListPane(): void;
  renderSidebarCategories(): void;
  renderDrawer(item: Item): void;
  applyShellViewClass(): void;
  setHash(view: VaultView, param?: string): void;
  openDrawer(): void;
  closeDrawer(): void;
  selectItemForDrawer(id: string): Promise<void>;
  openTypePanel(): void;
  closeTypePanel(): void;
  wireSidebar(): void;
  loadManifest(): Promise<void>;
}

// --- pure helpers (no state, no DOM dependencies beyond the args) ---

export function escapeHtml(str: string): string {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;');
}

export 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;
  }
}

export function typeLabel(t: ItemType): string {
  const labels: Record<ItemType, string> = {
    login: 'Login',
    secure_note: 'Secure Note',
    identity: 'Identity',
    card: 'Card',
    key: 'SSH / API Key',
    document: 'Document',
    totp: 'TOTP',
  };
  return labels[t];
}

export function getFilteredEntries(
  state: VaultState,
): Array<[ItemId, ManifestEntry]> {
  let filtered = state.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;
}
