import { useState, type FormEvent } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';

import { api } from '../api/client';
import type { CreatedApiToken } from '../api/bindings/CreatedApiToken';

function Interests() {
  const qc = useQueryClient();
  const interests = useQuery({ queryKey: ['interests'], queryFn: api.listInterests });
  const [label, setLabel] = useState('');
  const [weight, setWeight] = useState(0.5);

  const upsert = useMutation({
    mutationFn: (body: { label: string; weight: number }) => api.upsertInterest(body),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['interests'] }),
  });
  const remove = useMutation({
    mutationFn: (id: string) => api.deleteInterest(id),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['interests'] }),
  });

  const onAdd = (e: FormEvent) => {
    e.preventDefault();
    if (!label.trim()) return;
    upsert.mutate({ label: label.trim(), weight });
    setLabel('');
    setWeight(0.5);
  };

  return (
    <div className="card">
      <h2>Interests</h2>
      <p className="muted small">
        Positive weights pull matching stories up; negative weights bury them. These weights — and only these — decide
        your ranking.
      </p>

      <form className="row" onSubmit={onAdd}>
        <input
          className="grow"
          value={label}
          onChange={(e) => setLabel(e.target.value)}
          placeholder="topic, e.g. rust"
        />
        <input
          type="range"
          min={-1}
          max={1}
          step={0.05}
          value={weight}
          onChange={(e) => setWeight(Number(e.target.value))}
        />
        <span className="mono">{weight.toFixed(2)}</span>
        <button type="submit" className="primary">
          Add
        </button>
      </form>

      <ul className="list">
        {interests.data?.map((i) => (
          <li key={i.id} className="list-row">
            <strong>{i.label}</strong>
            <div className="list-row-end">
              <input
                type="range"
                min={-1}
                max={1}
                step={0.05}
                defaultValue={i.weight}
                onMouseUp={(e) => upsert.mutate({ label: i.label, weight: Number((e.target as HTMLInputElement).value) })}
                onTouchEnd={(e) =>
                  upsert.mutate({ label: i.label, weight: Number((e.target as HTMLInputElement).value) })
                }
              />
              <span className={`mono ${i.weight < 0 ? 'neg' : 'pos'}`}>{i.weight.toFixed(2)}</span>
              <button className="ghost" onClick={() => remove.mutate(i.id)}>
                ✕
              </button>
            </div>
          </li>
        ))}
        {interests.data?.length === 0 && <p className="muted empty">No interests yet.</p>}
      </ul>
    </div>
  );
}

function Tokens() {
  const qc = useQueryClient();
  const tokens = useQuery({ queryKey: ['tokens'], queryFn: api.listTokens });
  const [name, setName] = useState('');
  const [fresh, setFresh] = useState<CreatedApiToken | null>(null);

  const create = useMutation({
    mutationFn: () => api.createToken({ name: name.trim() }),
    onSuccess: (t) => {
      setFresh(t);
      setName('');
      qc.invalidateQueries({ queryKey: ['tokens'] });
    },
  });
  const revoke = useMutation({
    mutationFn: (id: string) => api.revokeToken(id),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['tokens'] }),
  });

  return (
    <div className="card">
      <h2>API tokens</h2>
      <p className="muted small">
        Agentic and algorithmic producers POST candidates to <code>/v1/ingest/candidates</code> with a bearer token.
        Each token is scoped to your feed.
      </p>

      <form
        className="row"
        onSubmit={(e) => {
          e.preventDefault();
          if (name.trim()) create.mutate();
        }}
      >
        <input className="grow" value={name} onChange={(e) => setName(e.target.value)} placeholder="token name" />
        <button type="submit" className="primary">
          Mint token
        </button>
      </form>

      {fresh && (
        <div className="secret">
          <p className="small">
            Copy this now — it won’t be shown again:
          </p>
          <code className="token">{fresh.secret}</code>
          <button className="ghost" onClick={() => setFresh(null)}>
            Done
          </button>
        </div>
      )}

      <ul className="list">
        {tokens.data?.map((t) => (
          <li key={t.id} className="list-row">
            <div>
              <strong>{t.name}</strong> <span className="mono muted">{t.prefix}…</span>
              {t.revoked_at && <span className="pill pill-revoked">revoked</span>}
            </div>
            {!t.revoked_at && (
              <button className="ghost" onClick={() => revoke.mutate(t.id)}>
                Revoke
              </button>
            )}
          </li>
        ))}
        {tokens.data?.length === 0 && <p className="muted empty">No tokens yet.</p>}
      </ul>
    </div>
  );
}

export function Settings() {
  return (
    <section>
      <header className="page-head">
        <h1>Settings</h1>
      </header>
      <div className="stack">
        <Interests />
        <Tokens />
      </div>
    </section>
  );
}
