/// Vault tab entry point — full "desktop-like" sidebar + pane layout.
///
/// Registers as the shared state host so popup components (item-detail,
/// item-form, trash, devices, settings, etc.) render natively in the
/// vault tab's pane area.

import type { Request, Response } from '../shared/messages';
import type {
  ItemId, ItemType, ManifestEntry, Item, VaultSettings, GeneratorRequest,
} from '../shared/types';
import { registerHost } from '../shared/state';
import { GLYPH_TRASH, GLYPH_DEVICES, GLYPH_SETTINGS, GLYPH_LOCK } from '../shared/glyphs';
import { renderItemDetail } from '../popup/components/item-detail';
import { renderItemForm } from '../popup/components/item-form';
import { renderTrash, teardown as teardownTrash } from '../popup/components/trash';
import { renderDevices, teardown as teardownDevices } from '../popup/components/devices';
import { renderSettings } from '../popup/components/settings';
import { renderVaultSettings as renderVaultSettingsView } from '../popup/components/settings-vault';
import { renderFieldHistory, teardown as teardownFieldHistory } from '../popup/components/field-history';
import { renderBackupPanel, teardown as teardownBackup } from './components/backup-panel';
import { renderImportPanel, teardown as teardownImport } from './components/import-panel';

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function sendMessage(request: Request): Promise<Response> {
  return new Promise((resolve) => {
    chrome.runtime.sendMessage(request, (response: Response) => {
      resolve(response);
    });
  });
}

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

function typeIcon(t: ItemType): string {
  switch (t) {
    case 'login':       return '\u{1F511}';  // key
    case 'secure_note': return '\u{1F4DD}';  // memo
    case 'identity':    return '\u{1FAAA}';  // id card
    case 'card':        return '\u{1F4B3}';  // credit card
    case 'key':         return '\u{1F5DD}';  // old key
    case 'document':    return '\u{1F4C4}';  // page facing up
    case 'totp':        return '⏱';      // stopwatch
  }
}

function typeLabel(t: ItemType): string {
  switch (t) {
    case 'login':       return 'Logins';
    case 'secure_note': return 'Secure Notes';
    case 'identity':    return 'Identities';
    case 'card':        return 'Cards';
    case 'key':         return 'Keys';
    case 'document':    return 'Documents';
    case 'totp':        return 'TOTP';
  }
}

// ---------------------------------------------------------------------------
// Hash routing
// ---------------------------------------------------------------------------

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

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

function parseHash(): HashRoute {
  const raw = window.location.hash.replace(/^#\/?/, '');
  if (!raw) return { view: 'list' };

  const parts = raw.split('/');
  const view = parts[0] as VaultView;

  switch (view) {
    case 'detail':
    case 'edit':
      return { view, id: parts[1] };
    case 'add':
      return { view, type: parts[1] };
    case 'trash':
    case 'devices':
    case 'settings':
    case 'settings-vault':
    case 'field-history':
    case 'backup':
    case 'import':
      return { view };
    default:
      return { view: 'list' };
  }
}

function setHash(view: VaultView, param?: string): void {
  const fragment = param ? `${view}/${param}` : view;
  window.location.hash = fragment === 'list' ? '' : fragment;
}

// ---------------------------------------------------------------------------
// State
// ---------------------------------------------------------------------------

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

const state: VaultState = {
  unlocked: false,
  view: 'list',
  entries: [],
  selectedId: null,
  selectedItem: null,
  selectedIndex: 0,
  searchQuery: '',
  activeGroup: null,
  vaultSettings: null,
  generatorDefaults: null,
  error: null,
  loading: false,
  newType: null,
  capturedTabId: null,
  capturedUrl: '',
  historyItemId: null,
};

// ---------------------------------------------------------------------------
// Register as shared state host
// ---------------------------------------------------------------------------

registerHost({
  getState: () => state,
  setState: (partial: any) => {
    Object.assign(state, partial);
    renderPane();
  },
  navigate: (view: string, extras?: any) => {
    Object.assign(state, { view, error: null, loading: false, ...extras });
    setHash(view as VaultView);
    renderSidebarList();
    renderPane();
  },
  sendMessage,
  escapeHtml,
  popOutToTab: () => {},
  isInTab: () => true,
  openVaultTab: () => {},
});

// ---------------------------------------------------------------------------
// Render entry point
// ---------------------------------------------------------------------------

function render(): void {
  const app = document.getElementById('vault-app');
  if (!app) return;

  if (!state.unlocked) {
    renderLockScreen(app);
  } else {
    renderShell(app);
  }
}

// ---------------------------------------------------------------------------
// Lock screen
// ---------------------------------------------------------------------------

function renderLockScreen(app: HTMLElement): void {
  app.innerHTML = `
    <div class="vault-lock-screen">
      <span class="brand">Relicario</span>
      <div class="vault-lock-screen__form">
        <input type="password" id="vault-passphrase" placeholder="passphrase" autocomplete="off" />
        <button class="btn btn-primary" id="vault-unlock-btn" style="width:100%;">unlock</button>
        ${state.error ? `<div class="error" style="text-align:center;">${escapeHtml(state.error)}</div>` : ''}
      </div>
    </div>
  `;

  const input = document.getElementById('vault-passphrase') as HTMLInputElement;
  const btn = document.getElementById('vault-unlock-btn')!;

  const doUnlock = async () => {
    const passphrase = input.value;
    if (!passphrase) return;
    btn.textContent = 'unlocking...';
    btn.setAttribute('disabled', 'true');
    const resp = await sendMessage({ type: 'unlock', passphrase });
    if (resp.ok) {
      state.unlocked = true;
      state.error = null;
      await loadManifest();
      render();
    } else {
      state.error = resp.error ?? 'unlock failed';
      render();
    }
  };

  btn.addEventListener('click', doUnlock);
  input.addEventListener('keydown', (e) => {
    if (e.key === 'Enter') doUnlock();
  });
  input.focus();
}

// ---------------------------------------------------------------------------
// Shell (sidebar + pane)
// ---------------------------------------------------------------------------

function renderShell(app: HTMLElement): void {
  // Only create the shell structure if it's not present yet
  if (!app.querySelector('.vault-sidebar')) {
    app.innerHTML = `
      <div class="vault-sidebar">
        <div class="vault-sidebar__header">
          <span class="brand">Relicario</span>
        </div>
        <div class="vault-sidebar__search">
          <input type="text" id="vault-search" placeholder="/ search..." />
        </div>
        <div class="vault-sidebar__list" id="vault-sidebar-list"></div>
        <div class="vault-sidebar__nav">
          <button class="vault-sidebar__nav-item" data-nav="add">+ new item</button>
          <button class="vault-sidebar__nav-item" data-nav="trash">${GLYPH_TRASH} trash</button>
          <button class="vault-sidebar__nav-item" data-nav="devices">${GLYPH_DEVICES} devices</button>
          <button class="vault-sidebar__nav-item" data-nav="settings">${GLYPH_SETTINGS} settings</button>
          <button class="vault-sidebar__nav-item" data-nav="lock">${GLYPH_LOCK} lock</button>
        </div>
      </div>
      <div class="vault-pane vault-pane--empty" id="vault-pane">
        select an item
      </div>
    `;
    wireSidebar();
  }

  renderSidebarList();
  renderPane();
}

// ---------------------------------------------------------------------------
// Sidebar wiring
// ---------------------------------------------------------------------------

function wireSidebar(): void {
  // Search
  const searchInput = document.getElementById('vault-search') as HTMLInputElement | null;
  searchInput?.addEventListener('input', () => {
    state.searchQuery = searchInput.value;
    renderSidebarList();
  });

  // Nav buttons
  document.querySelectorAll('.vault-sidebar__nav-item').forEach((btn) => {
    btn.addEventListener('click', async () => {
      const nav = (btn as HTMLElement).dataset.nav;
      if (nav === 'lock') {
        await sendMessage({ type: 'lock' });
        state.unlocked = false;
        state.selectedId = null;
        state.selectedItem = null;
        state.entries = [];
        render();
        return;
      }
      if (nav === 'add') {
        state.selectedId = null;
        state.selectedItem = null;
        state.newType = null;
        setHash('add');
        renderPane();
        return;
      }
      if (nav === 'trash' || nav === 'devices' || nav === 'settings') {
        state.selectedId = null;
        state.selectedItem = null;
        state.newType = null;
        setHash(nav);
        renderPane();
        return;
      }
    });
  });

  // Global "/" shortcut to focus search
  document.addEventListener('keydown', (e) => {
    if (e.key === '/' && !isEditableTarget(e.target)) {
      e.preventDefault();
      searchInput?.focus();
    }
  });
}

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

// ---------------------------------------------------------------------------
// Sidebar list
// ---------------------------------------------------------------------------

function getFilteredEntries(): 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;
}

function renderSidebarList(): void {
  const container = document.getElementById('vault-sidebar-list');
  if (!container) return;

  const filtered = getFilteredEntries();

  // Group by type
  const groups = new Map<ItemType, Array<[ItemId, ManifestEntry]>>();
  for (const entry of filtered) {
    const t = entry[1].type;
    if (!groups.has(t)) groups.set(t, []);
    groups.get(t)!.push(entry);
  }

  if (filtered.length === 0) {
    container.innerHTML = '<div class="empty">no items</div>';
    return;
  }

  let html = '';
  // Stable type ordering
  const typeOrder: ItemType[] = ['login', 'secure_note', 'identity', 'card', 'key', 'document', 'totp'];
  for (const t of typeOrder) {
    const items = groups.get(t);
    if (!items || items.length === 0) continue;
    html += `<div class="vault-group-header">${typeIcon(t)} ${escapeHtml(typeLabel(t))}</div>`;
    for (const [id, e] of items) {
      const sel = id === state.selectedId ? ' selected' : '';
      const meta = e.icon_hint ? escapeHtml(e.icon_hint) : '';
      html += `
        <div class="vault-entry${sel}" data-id="${escapeHtml(id)}">
          <span class="vault-entry__title">${escapeHtml(e.title)}</span>
          ${meta ? `<span class="vault-entry__meta">${meta}</span>` : ''}
        </div>
      `;
    }
  }

  container.innerHTML = html;

  // Wire clicks
  container.querySelectorAll('.vault-entry').forEach((el) => {
    el.addEventListener('click', async () => {
      const id = (el as HTMLElement).dataset.id!;
      await selectItem(id);
    });
  });
}

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

// ---------------------------------------------------------------------------
// Pane rendering — delegates to shared popup components
// ---------------------------------------------------------------------------

function teardownPaneComponents(): void {
  teardownTrash();
  teardownDevices();
  teardownFieldHistory();
  teardownBackup();
  teardownImport();
}

function renderPane(): void {
  const pane = document.getElementById('vault-pane');
  if (!pane) return;

  teardownPaneComponents();

  const route = parseHash();
  // Keep state.view in sync with hash for components that read it
  state.view = route.view;

  pane.className = 'vault-pane';

  switch (route.view) {
    case 'detail':
      if (state.selectedItem) {
        renderItemDetail(pane);
      } else {
        pane.className = 'vault-pane vault-pane--empty';
        pane.innerHTML = 'select an item';
      }
      break;
    case 'add':
      // Prefer hash type for deep-links; otherwise keep the in-memory value
      // set by the type-selection click handler (which calls setState →
      // renderPane before the URL hash has been updated to include the type).
      state.newType = (route.type as ItemType) ?? state.newType ?? null;
      renderItemForm(pane, 'add');
      break;
    case 'edit':
      renderItemForm(pane, 'edit');
      break;
    case 'trash':
      renderTrash(pane);
      break;
    case 'devices':
      renderDevices(pane);
      break;
    case 'settings':
      renderSettings(pane);
      break;
    case 'settings-vault':
      renderVaultSettingsView(pane);
      break;
    case 'field-history':
      renderFieldHistory(pane);
      break;
    case 'backup':
      renderBackupPanel(pane);
      break;
    case 'import':
      renderImportPanel(pane);
      break;
    default:
      pane.className = 'vault-pane vault-pane--empty';
      pane.innerHTML = 'select an item';
      break;
  }
}

// ---------------------------------------------------------------------------
// Data loading
// ---------------------------------------------------------------------------

async function loadManifest(): Promise<void> {
  const listResp = await sendMessage({ type: 'list_items' });
  if (listResp.ok) {
    const data = listResp.data as { items: Array<[ItemId, ManifestEntry]> };
    state.entries = data.items;
  }

  const vsResp = await sendMessage({ type: 'get_vault_settings' });
  if (vsResp.ok) {
    const data = vsResp.data as { settings: VaultSettings };
    state.vaultSettings = data.settings;
    state.generatorDefaults = data.settings.generator_defaults;
  }

  // Handle deep link from hash
  const route = parseHash();
  if (route.view === 'detail' && route.id) {
    const itemResp = await sendMessage({ type: 'get_item', id: route.id });
    if (itemResp.ok) {
      const data = itemResp.data as { item: Item };
      state.selectedId = route.id;
      state.selectedItem = data.item;
    }
  }
}

// ---------------------------------------------------------------------------
// Init
// ---------------------------------------------------------------------------

document.addEventListener('DOMContentLoaded', async () => {
  // Check if already unlocked
  const resp = await sendMessage({ type: 'is_unlocked' });
  if (resp.ok) {
    const data = resp.data as { unlocked: boolean };
    if (data.unlocked) {
      state.unlocked = true;
      await loadManifest();
    }
  }

  render();

  // Session expired listener
  chrome.runtime.onMessage.addListener((msg) => {
    if (msg.type === 'session_expired') {
      state.unlocked = false;
      state.selectedId = null;
      state.selectedItem = null;
      state.entries = [];
      state.error = null;
      render();
    }
  });

  // Hash change listener
  window.addEventListener('hashchange', () => {
    if (!state.unlocked) return;

    const route = parseHash();

    // If navigating to a detail/edit view for an item we already have loaded
    if ((route.view === 'detail' || route.view === 'edit') && route.id) {
      if (state.selectedId === route.id && state.selectedItem) {
        renderPane();
        renderSidebarList();
        return;
      }
      // Need to fetch the item
      selectItem(route.id);
      return;
    }

    // For non-item views, just re-render the pane
    state.selectedId = null;
    state.selectedItem = null;
    renderSidebarList();
    renderPane();
  });
});
