// Search & Investigation view

// Match a free-form query against canned NL_QUERIES; if it matches keywords, return canned results.
// Otherwise, fuzzy-match track captions/attributes.
function searchTracks(query) {
  const q = query.trim().toLowerCase();
  if (!q) return [];

  // 1) Find best canned match
  let canned = null;
  let bestScore = 0;
  for (const nq of NL_QUERIES) {
    if (q === nq.q.toLowerCase()) { canned = nq; bestScore = 999; break; }
    let score = 0;
    for (const kw of nq.keywords) if (q.includes(kw.toLowerCase())) score += 1;
    if (score > bestScore) { bestScore = score; canned = nq; }
  }
  if (canned && bestScore > 0) {
    return canned.results.map((r) => ({ track: lookupTrack(r.trackId), relevance: r.relevance }));
  }
  // 2) Fallback: text search across captions
  return TRACKS
    .map((t) => {
      const blob = [
        t.caption,
        JSON.stringify(t.attributes?.clothing || {}),
        (t.attributes?.carrying || []).join(' '),
        JSON.stringify(t.attributes?.vehicle || {}),
        t.class,
      ].join(' ').toLowerCase();
      const tokens = q.split(/\s+/).filter(Boolean);
      const hits = tokens.filter((w) => blob.includes(w)).length;
      const rel = hits / Math.max(1, tokens.length);
      return rel > 0 ? { track: t, relevance: 0.55 + rel * 0.35 } : null;
    })
    .filter(Boolean)
    .sort((a, b) => b.relevance - a.relevance);
}

function ResultCard({ result, onOpen, scoreLabel = 'relevance' }) {
  const { t } = useI18n();
  const trk = result.track;
  if (!trk) return null;
  const cam = lookupCamera(trk.camera_id);
  const zone = lookupZone(trk.zones_visited?.[0]);
  const identity = lookupIdentity(trk.identity_id);
  const trkIdx = parseInt(trk.id.split('-')[1], 10) - 1000;
  const ts = Date.now() - (trkIdx + 1) * 137 * 1000;
  const scorePct = Math.round(result.relevance * 100);
  return (
    <button
      onClick={() => onOpen(trk)}
      className="group text-left bg-slate-850/40 border border-slate-700/60 rounded-md overflow-hidden hover:border-forest-500/60 hover:bg-slate-850/80 transition-all"
    >
      <div className="aspect-video relative bg-slate-800">
        <SyntheticThumb camera={cam} track={trk} className="absolute inset-0" showBox />
        {zone && <ZoneOverlay zone={zone} faint />}
        {/* Score badge */}
        <div className="absolute top-2 right-2 inline-flex items-center gap-1.5 px-2 py-0.5 rounded-sm bg-black/60 backdrop-blur-sm">
          <div className="w-12 h-1 bg-slate-700 rounded-full overflow-hidden">
            <div
              className="h-full bg-forest-500"
              style={{ width: `${scorePct}%` }}
            />
          </div>
          <span className="font-mono text-[10px] text-forest-300">{scorePct}%</span>
        </div>
        <div className="absolute top-2 left-2 inline-flex items-center gap-1 px-1.5 py-0.5 rounded-sm bg-black/60 backdrop-blur-sm">
          <ClassIcon cls={trk.class} size={11} className="text-white" />
          <span className="text-[10px] font-mono text-white">{t(`class.${trk.class}`)}</span>
        </div>
        <div className="absolute inset-x-0 bottom-0 px-2 py-1.5 flex items-center justify-between gap-1 text-[10px] font-mono text-white">
          <span className="truncate drop-shadow">{cam?.name}</span>
          <span className="opacity-80 drop-shadow">{formatTime(ts)}</span>
        </div>
      </div>
      <div className="p-3">
        <p className="text-[12px] text-slate-200 leading-snug line-clamp-2">"{trk.caption}"</p>
        <div className="flex items-center gap-1.5 mt-2 flex-wrap">
          {identity && (
            <Pill tone="forest">
              <IdentityAvatar identity={identity} size={11} />
              {identity.name}
            </Pill>
          )}
          {!identity && <Pill tone="ghost"><Icons.Person size={11} /> {t('modal.unknown')}</Pill>}
          {zone && (
            <Pill tone="ghost">
              <span className="w-1 h-1 rounded-full" style={{ background: ZONE_ROLES[zone.semantic_role]?.color }} />
              {zone.name}
            </Pill>
          )}
        </div>
      </div>
    </button>
  );
}

// Identity timeline visualization
function IdentityTimeline({ identityId, onOpenTrack }) {
  const { t } = useI18n();
  const id = lookupIdentity(identityId);
  if (!id) return null;
  const tracks = TRACKS
    .map((trk, i) => ({ trk, idx: i }))
    .filter(({ trk }) => trk.identity_id === identityId)
    .map(({ trk, idx }) => ({ trk, ts: Date.now() - (idx + 1) * 137 * 1000 }))
    .sort((a, b) => b.ts - a.ts);
  if (tracks.length === 0) return null;
  const firstTs = tracks[tracks.length - 1].ts;
  const lastTs = tracks[0].ts;
  return (
    <Section
      title={
        <>
          <Icons.Clock size={13} />
          {t('search.timeline')} · <span className="text-slate-100">{id.name}</span>
        </>
      }
      dense
    >
      <div className="p-4">
        <div className="flex items-center gap-3 mb-4">
          <IdentityAvatar identity={id} size={36} />
          <div>
            <div className="font-medium text-slate-100 text-sm">{id.name}</div>
            <div className="text-[11px] text-slate-400">{id.role}</div>
          </div>
          <div className="ml-auto text-right">
            <div className="text-[10px] uppercase tracking-wider text-slate-500">{t('search.timeline.lastSeen')}</div>
            <div className="text-[12px] text-slate-200 font-mono">{formatDateTime(lastTs)}</div>
          </div>
        </div>
        {/* Timeline track */}
        <div className="relative">
          <div className="h-1 bg-slate-750 rounded-full" />
          {tracks.map((entry, i) => {
            const range = Math.max(1, lastTs - firstTs);
            const x = ((entry.ts - firstTs) / range) * 100;
            return (
              <button
                key={entry.trk.id}
                onClick={() => onOpenTrack(entry.trk)}
                className="absolute -translate-x-1/2 group"
                style={{ left: `${x}%`, top: -4 }}
                title={`${formatDateTime(entry.ts)} · ${lookupCamera(entry.trk.camera_id)?.name}`}
              >
                <div className="w-3 h-3 rounded-full bg-forest-500 border-2 border-navy-900 group-hover:scale-125 transition-transform" />
              </button>
            );
          })}
          <div className="flex justify-between mt-2 font-mono text-[10px] text-slate-500">
            <span>{formatDateTime(firstTs)}</span>
            <span>{formatDateTime(lastTs)}</span>
          </div>
        </div>
        {/* Recent appearances */}
        <div className="mt-4 grid grid-cols-2 sm:grid-cols-4 gap-2">
          {tracks.slice(0, 4).map(({ trk, ts }) => {
            const cam = lookupCamera(trk.camera_id);
            return (
              <button
                key={trk.id}
                onClick={() => onOpenTrack(trk)}
                className="text-left bg-slate-850/40 border border-slate-700/60 rounded overflow-hidden hover:border-forest-500/60 transition-colors"
              >
                <div className="aspect-video relative">
                  <SyntheticThumb camera={cam} track={trk} className="absolute inset-0" showBox />
                </div>
                <div className="p-1.5">
                  <div className="text-[11px] text-slate-200 truncate">{cam?.name}</div>
                  <div className="text-[10px] font-mono text-slate-500">{formatTime(ts)}</div>
                </div>
              </button>
            );
          })}
        </div>
      </div>
    </Section>
  );
}

function ReidPanel({ track, onOpenTrack }) {
  const { t } = useI18n();
  const hits = (REID[track.id] || []).map((r) => ({ track: lookupTrack(r.trackId), sim: r.sim }));
  return (
    <Section
      title={
        <>
          <Icons.Scan size={13} />
          {t('search.reid.title')}
        </>
      }
      dense
    >
      <div className="p-3">
        <div className="text-[11px] text-slate-400 mb-3">{t('search.reid.subtitle')}</div>
        <div className="flex items-stretch gap-2">
          <div className="w-32 shrink-0">
            <div className="aspect-video relative rounded overflow-hidden border-2 border-forest-500/60 bg-slate-800">
              <SyntheticThumb camera={lookupCamera(track.camera_id)} track={track} className="absolute inset-0" showBox />
              <div className="absolute inset-0 ring-2 ring-forest-500/30" />
            </div>
            <div className="text-[10px] text-forest-400 font-mono uppercase tracking-wider text-center mt-1">Alvo</div>
          </div>
          <div className="flex-1 grid grid-cols-2 sm:grid-cols-3 gap-2 min-w-0">
            {hits.length === 0 && (
              <div className="col-span-full text-[12px] text-slate-500 italic px-4 py-6 text-center">
                Sem outras correspondências de alta confiança.
              </div>
            )}
            {hits.map(({ track: trk, sim }) => {
              if (!trk) return null;
              const cam = lookupCamera(trk.camera_id);
              return (
                <button
                  key={trk.id}
                  onClick={() => onOpenTrack(trk)}
                  className="text-left rounded overflow-hidden border border-slate-700/60 hover:border-forest-500/60 transition-colors"
                >
                  <div className="aspect-video relative bg-slate-800">
                    <SyntheticThumb camera={cam} track={trk} className="absolute inset-0" showBox />
                    <div className="absolute top-1 right-1 inline-flex items-center gap-1 px-1.5 py-0.5 rounded-sm bg-black/60 backdrop-blur-sm">
                      <span className="font-mono text-[10px] text-forest-300">{Math.round(sim * 100)}%</span>
                    </div>
                  </div>
                  <div className="p-1.5">
                    <div className="text-[11px] text-slate-200 truncate">{cam?.name}</div>
                    <div className="text-[10px] font-mono text-slate-500">{trk.id}</div>
                  </div>
                </button>
              );
            })}
          </div>
        </div>
      </div>
    </Section>
  );
}

function SearchView({ initialFindAgainTrack }) {
  const { t } = useI18n();
  const [query, setQuery] = React.useState('');
  const [submitted, setSubmitted] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const [openTrack, setOpenTrack] = React.useState(null);
  const [reidTrack, setReidTrack] = React.useState(initialFindAgainTrack || null);
  const [timelineId, setTimelineId] = React.useState(initialFindAgainTrack?.identity_id || null);
  const [filters, setFilters] = React.useState({ timeRange: '24h', cameraId: null, zoneId: null, class: null, identityId: null, clothingColor: null, carrying: null });

  // Rotating placeholders
  const [phIndex, setPhIndex] = React.useState(0);
  React.useEffect(() => {
    const id = setInterval(() => setPhIndex((i) => (i + 1) % NL_PLACEHOLDERS.length), 3500);
    return () => clearInterval(id);
  }, []);

  React.useEffect(() => {
    if (initialFindAgainTrack) {
      setReidTrack(initialFindAgainTrack);
      setTimelineId(initialFindAgainTrack.identity_id || null);
    }
  }, [initialFindAgainTrack]);

  const results = React.useMemo(() => {
    if (!submitted) return [];
    let r = searchTracks(submitted);
    // Apply filters
    r = r.filter(({ track }) => {
      if (filters.cameraId && track.camera_id !== filters.cameraId) return false;
      if (filters.zoneId && !track.zones_visited?.includes(filters.zoneId)) return false;
      if (filters.class && track.class !== filters.class) return false;
      if (filters.identityId && track.identity_id !== filters.identityId) return false;
      if (filters.clothingColor) {
        const blob = JSON.stringify(track.attributes?.clothing || {}).toLowerCase();
        if (!blob.includes(filters.clothingColor.toLowerCase())) return false;
      }
      if (filters.carrying) {
        const has = (track.attributes?.carrying || []).some((c) => c.toLowerCase().includes(filters.carrying.toLowerCase()));
        if (!has) return false;
      }
      return true;
    });
    return r;
  }, [submitted, filters]);

  function submit(q) {
    const qstr = (typeof q === 'string' ? q : query).trim();
    if (!qstr) return;
    setQuery(qstr);
    setLoading(true);
    setSubmitted(null);
    // Simulate latency
    setTimeout(() => { setSubmitted(qstr); setLoading(false); }, 480);
  }

  function clearFilter(k) {
    setFilters((f) => ({ ...f, [k]: null }));
  }

  const activeFilters = Object.entries(filters).filter(([k, v]) => v && k !== 'timeRange');
  const cameraOpts = [{ value: null, label: 'Todas as câmaras' }, ...CAMERAS.map((c) => ({ value: c.id, label: c.name }))];
  const zoneOpts = [{ value: null, label: 'Todas as zonas' }, ...ZONES.map((z) => ({ value: z.id, label: z.name }))];
  const idOpts = [{ value: null, label: 'Qualquer identidade' }, ...IDENTITIES.map((i) => ({ value: i.id, label: i.name }))];
  const classOpts = [{ value: null, label: 'Qualquer classe' }, ...['person', 'vehicle', 'animal'].map((c) => ({ value: c, label: t(`class.${c}`) }))];
  const timeOpts = [
    { value: '1h', label: 'Última hora' },
    { value: '24h', label: 'Últimas 24h' },
    { value: '7d', label: 'Últimos 7 dias' },
    { value: '30d', label: 'Últimos 30 dias' },
  ];
  const colorOpts = [{ value: null, label: 'Qualquer cor' }, ...['preta', 'branca', 'azul', 'vermelha', 'cinza', 'laranja'].map((c) => ({ value: c, label: c }))];
  const carryOpts = [{ value: null, label: 'Qualquer' }, ...['mochila', 'pasta', 'rádio', 'carrinho'].map((c) => ({ value: c, label: c }))];

  return (
    <div className="flex flex-col h-full min-h-0 overflow-auto">
      <div className="px-5 pt-5 pb-3 shrink-0">
        <h1 className="font-display text-xl font-semibold text-slate-100">{t('search.title')}</h1>
        <p className="text-[13px] text-slate-400 mt-0.5">{t('search.subtitle')}</p>
      </div>

      {/* Search bar */}
      <div className="px-5 pb-3 shrink-0">
        <div className="relative">
          <div className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400">
            <Icons.Search size={18} />
          </div>
          <input
            type="text"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter') submit(); }}
            placeholder={NL_PLACEHOLDERS[phIndex]}
            className="w-full h-14 pl-12 pr-32 bg-slate-850/80 border border-slate-700/70 focus:border-forest-500 focus:bg-navy-900 rounded-lg text-[15px] text-slate-100 placeholder:text-slate-500 placeholder:italic outline-none transition-colors"
          />
          <button
            onClick={() => submit()}
            className="absolute right-2 top-1/2 -translate-y-1/2 inline-flex items-center gap-1.5 h-10 px-4 bg-forest-600 hover:bg-forest-500 text-white rounded font-medium text-sm border border-forest-500 transition-colors"
          >
            <Icons.Bolt size={14} />
            {t('search.button')}
          </button>
        </div>
        {/* Example chips */}
        <div className="mt-2.5 flex items-center gap-1.5 flex-wrap">
          <span className="text-[10px] uppercase tracking-wider text-slate-500 mr-1">{t('search.examples')}:</span>
          {NL_PLACEHOLDERS.slice(0, 5).map((p) => (
            <button
              key={p}
              onClick={() => submit(p)}
              className="text-[11px] px-2 py-1 rounded-full bg-slate-850 hover:bg-slate-800 border border-slate-700/60 text-slate-300 italic transition-colors"
            >
              "{p}"
            </button>
          ))}
        </div>
      </div>

      {/* Filters bar */}
      <div className="px-5 pb-3 shrink-0">
        <div className="bg-slate-850/40 border border-slate-700/60 rounded-md p-2.5 flex items-center gap-2 flex-wrap">
          <span className="text-[10px] uppercase tracking-wider text-slate-500 mr-1 font-medium">{t('search.filters')}</span>
          <Dropdown icon={Icons.Clock} value={filters.timeRange} onChange={(v) => setFilters((f) => ({ ...f, timeRange: v }))} options={timeOpts} />
          <Dropdown icon={Icons.Video} value={filters.cameraId} onChange={(v) => setFilters((f) => ({ ...f, cameraId: v }))} options={cameraOpts} />
          <Dropdown icon={Icons.Polygon} value={filters.zoneId} onChange={(v) => setFilters((f) => ({ ...f, zoneId: v }))} options={zoneOpts} />
          <Dropdown icon={Icons.Person} value={filters.class} onChange={(v) => setFilters((f) => ({ ...f, class: v }))} options={classOpts} />
          <Dropdown icon={Icons.Users} value={filters.identityId} onChange={(v) => setFilters((f) => ({ ...f, identityId: v }))} options={idOpts} />
          <Dropdown icon={Icons.Filter} value={filters.clothingColor} onChange={(v) => setFilters((f) => ({ ...f, clothingColor: v }))} options={colorOpts} />
          <Dropdown icon={Icons.Backpack} value={filters.carrying} onChange={(v) => setFilters((f) => ({ ...f, carrying: v }))} options={carryOpts} />
          {activeFilters.length > 0 && (
            <button
              onClick={() => setFilters({ timeRange: '24h', cameraId: null, zoneId: null, class: null, identityId: null, clothingColor: null, carrying: null })}
              className="text-[11px] text-slate-400 hover:text-slate-200 underline ml-auto"
            >
              Limpar filtros ({activeFilters.length})
            </button>
          )}
        </div>
      </div>

      {/* Results / Reid / Timeline */}
      <div className="flex-1 min-h-0 px-5 pb-5 space-y-4">
        {/* Reid panel (sticky if a track was selected for Find Again) */}
        {reidTrack && (
          <ReidPanel track={reidTrack} onOpenTrack={(t) => setOpenTrack(t)} />
        )}

        {/* Timeline */}
        {timelineId && (
          <IdentityTimeline identityId={timelineId} onOpenTrack={(t) => setOpenTrack(t)} />
        )}

        {/* Results */}
        {(submitted || loading) && (
          <Section
            title={
              <>
                <Icons.Search size={13} />
                {loading ? (
                  <span className="text-slate-400">a pesquisar...</span>
                ) : (
                  <>
                    <span className="text-slate-300">"<span className="text-slate-100">{submitted}</span>"</span>
                    <span className="ml-2 text-[10px] font-mono text-slate-500">{results.length} {t('search.results')}</span>
                  </>
                )}
              </>
            }
            dense
          >
            <div className="p-3">
              {loading ? (
                <div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-3">
                  {[0, 1, 2, 3].map((i) => (
                    <div key={i} className="aspect-[4/3] rounded-md bg-slate-850/40 border border-slate-700/40 animate-pulse" />
                  ))}
                </div>
              ) : results.length === 0 ? (
                <div className="text-center py-10 text-slate-500 text-sm">Sem resultados para esta consulta.</div>
              ) : (
                <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">
                  {results.map((r) => (
                    <ResultCard key={r.track.id} result={r} onOpen={(trk) => setOpenTrack(trk)} />
                  ))}
                </div>
              )}
            </div>
          </Section>
        )}

        {/* Empty state when no search */}
        {!submitted && !loading && !reidTrack && (
          <div className="text-center py-16">
            <div className="inline-flex items-center justify-center w-16 h-16 rounded-full bg-forest-500/10 border border-forest-500/30 mb-4">
              <Icons.Search size={28} className="text-forest-400" />
            </div>
            <h3 className="font-display text-lg font-semibold text-slate-100">Pesquisa semântica de vídeo</h3>
            <p className="text-[13px] text-slate-400 max-w-md mx-auto mt-2 leading-relaxed">
              Descreva uma pessoa, veículo ou comportamento em linguagem natural. O VeraCam procura significado, não palavras-chave, em todos os registos retidos.
            </p>
          </div>
        )}
      </div>

      {openTrack && (
        <ClipModal
          track={openTrack}
          onClose={() => setOpenTrack(null)}
          onFindAgain={(trk) => {
            setOpenTrack(null);
            setReidTrack(trk);
            setTimelineId(trk?.identity_id || null);
            window.scrollTo({ top: 0 });
          }}
        />
      )}
    </div>
  );
}

window.SearchView = SearchView;
