import { Component, useEffect, useState, type ErrorInfo, type ReactNode } from 'react';
import { useInventorySearch } from './useInventorySearch';
import { FilterSidebar } from './FilterSidebar';
import { ActiveChips } from './ActiveChips';
import { ResultsTable } from './ResultsTable';
import { DetailPanel } from './DetailPanel';
import type { InvItem } from './types';

/** Composite key used to re-match a selected item across refetches (objects are recreated each fetch). */
function itemKey(i: InvItem): string {
  return `${i.name} ${i.character_name} ${i.last_updated ?? ''}`;
}

class InventorySearchErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean }> {
  constructor(props: { children: ReactNode }) {
    super(props);
    this.state = { hasError: false };
  }
  static getDerivedStateFromError(): { hasError: boolean } {
    return { hasError: true };
  }
  componentDidCatch(error: Error, info: ErrorInfo): void {
    console.error('Inventory search crashed:', error, info);
  }
  render(): ReactNode {
    if (this.state.hasError) {
      return (
        <div className="inv-page">
          <div className="inv-error" style={{ margin: 'auto', textAlign: 'center', padding: 24 }}>
            <p style={{ marginBottom: 12 }}>Something went wrong loading the inventory search page.</p>
            <button className="inv-btn" onClick={() => { window.location.href = '/?view=inventory'; }}>
              Reset filters
            </button>
          </div>
        </div>
      );
    }
    return this.props.children;
  }
}

function InventorySearchPageInner() {
  const search = useInventorySearch();
  const [selected, setSelected] = useState<InvItem | null>(null);

  // Selection is by object identity; every refetch produces new item objects, so re-match the
  // previously selected item by composite key in the new result set (or clear it if it's gone).
  useEffect(() => {
    if (!selected) return;
    const items = search.result?.items ?? [];
    const key = itemKey(selected);
    const match = items.find(i => itemKey(i) === key);
    if (match && match !== selected) setSelected(match);
    else if (!match) setSelected(null);
  }, [search.result]);

  return (
    <div className="inv-page">
      <div className="inv-topbar">
        <span className="inv-title">⚔ Inventory Search</span>
        <input
          className="inv-searchbox"
          placeholder="Search name or material…"
          value={search.filters.text}
          onChange={e => search.update({ text: e.target.value })}
        />
        <button className="inv-btn" onClick={() => { search.reset(); setSelected(null); }}>Reset</button>
        <span className="inv-count">
          {search.error ? <span className="inv-error">{search.error}</span>
            : search.result ? <><b>{search.result.total_count.toLocaleString()}</b> items
                {search.queryMs != null && <> · {search.queryMs} ms</>}
                {search.loading && ' · …'}</>
            : 'loading…'}
        </span>
      </div>
      <ActiveChips search={search} />
      <div className="inv-main">
        <FilterSidebar search={search} />
        <ResultsTable search={search} selected={selected} onSelect={setSelected} />
        {selected && <DetailPanel item={selected} onClose={() => setSelected(null)} />}
      </div>
    </div>
  );
}

export function InventorySearchPage() {
  return (
    <InventorySearchErrorBoundary>
      <InventorySearchPageInner />
    </InventorySearchErrorBoundary>
  );
}
