import { useEffect, useMemo, useState } from "react";
import {
  callSkill,
  fileToBrowserDocument,
  loadAgentConfig,
  loadSession,
  signInUrl,
  successFixture,
} from "./a2a.js";

const emptyQuote = { vendor: "", unit_price: 0, quantity: 1, delivery_days: 1, warranty_months: 0 };

export function App() {
  const [config, setConfig] = useState(null);
  const [session, setSession] = useState(null);
  const [comparisonId, setComparisonId] = useState("studio-quote-v1");
  const [quotes, setQuotes] = useState(successFixture().quotes);
  const [weights, setWeights] = useState(successFixture().weights);
  const [documents, setDocuments] = useState([]);
  const [result, setResult] = useState(null);
  const [history, setHistory] = useState([]);
  const [error, setError] = useState(null);
  const [running, setRunning] = useState(false);

  useEffect(() => {
    loadAgentConfig()
      .then(async (data) => {
        setConfig(data);
        try {
          setSession(await loadSession(data));
        } catch {
          setSession({ authenticated: false });
        }
      })
      .catch((err) => setError(err.message || String(err)));
  }, []);

  const needsSignIn = Boolean(config?.auth?.invokeRequiresSession && session && !session.authenticated);
  const signInHref = useMemo(() => (config ? signInUrl(config) : null), [config]);
  const totalWeight = Number(weights.price) + Number(weights.delivery) + Number(weights.warranty);

  function setQuote(index, field, value) {
    setQuotes((items) => items.map((quote, i) => (i === index ? { ...quote, [field]: value } : quote)));
  }

  function normalizeQuote(quote) {
    return {
      vendor: quote.vendor.trim(),
      unit_price: Number(quote.unit_price),
      quantity: Number.parseInt(quote.quantity, 10),
      delivery_days: Number.parseInt(quote.delivery_days, 10),
      warranty_months: Number.parseInt(quote.warranty_months, 10),
    };
  }

  function normalizeWeights() {
    return {
      price: Number(weights.price),
      delivery: Number(weights.delivery),
      warranty: Number(weights.warranty),
    };
  }

  function validate() {
    if (needsSignIn) return "Sign in to run QuoteJudge.";
    if (!comparisonId.trim()) return "Comparison ID is required.";
    if (documents.length === 0 && quotes.length < 2) return "Enter at least two quotes.";
    if (totalWeight <= 0) return "At least one weight must be greater than zero.";
    for (const quote of quotes) {
      if (documents.length === 0 && !quote.vendor.trim()) return "Every quote needs a vendor name.";
    }
    return null;
  }

  async function runComparison(event) {
    event.preventDefault();
    if (!config) return;
    const problem = validate();
    if (problem) {
      setError(problem);
      return;
    }
    setRunning(true);
    setError(null);
    setResult(null);
    try {
      const skill = documents.length ? "compare_quotes_browser_upload" : "compare_quotes";
      const args = documents.length
        ? { comparison_id: comparisonId.trim(), weights: normalizeWeights(), documents }
        : { comparison_id: comparisonId.trim(), quotes: quotes.map(normalizeQuote), weights: normalizeWeights() };
      const data = await callSkill(config, skill, args);
      if (!data?.ok) throw new Error(data?.message || data?.code || "Comparison failed.");
      setResult(data);
      setHistory((items) => [data, ...items.filter((item) => item.comparison_id !== data.comparison_id)].slice(0, 5));
    } catch (err) {
      if (err.status === 401 && signInHref) setError("Session expired. Sign in again to continue.");
      else setError(err.message || String(err));
    } finally {
      setRunning(false);
    }
  }

  async function reloadComparison(id = comparisonId) {
    if (!config) return;
    setRunning(true);
    setError(null);
    try {
      const data = await callSkill(config, "get_comparison", { comparison_id: id.trim() });
      if (!data?.ok) throw new Error(data?.message || data?.code || "No saved comparison found.");
      setResult(data);
      setHistory((items) => [data, ...items.filter((item) => item.comparison_id !== data.comparison_id)].slice(0, 5));
    } catch (err) {
      setError(err.message || String(err));
    } finally {
      setRunning(false);
    }
  }

  async function onFilesSelected(event) {
    const files = Array.from(event.target.files || []);
    setError(null);
    try {
      const docs = [];
      for (const file of files.slice(0, 3)) docs.push(await fileToBrowserDocument(file));
      setDocuments(docs);
    } catch (err) {
      setError(err.message || String(err));
      setDocuments([]);
    }
  }

  if (!config) {
    return <main className="loading"><p>{error || "Loading QuoteJudge Studio..."}</p></main>;
  }

  return (
    <main className="app-shell">
      <section className="hero">
        <div>
          <p className="eyebrow">QuoteJudge Studio · {config.agent.version}</p>
          <h1>Choose the best vendor quote with auditable weights.</h1>
          <p>
            Paste quotes or upload a small CSV/JSON file, balance price, delivery, and warranty,
            then persist the recommendation in managed Postgres for your signed-in user.
          </p>
        </div>
        <div className="session-card">
          <span>{session?.authenticated ? "Signed in" : "Signed out"}</span>
          <strong>{session?.user?.email || session?.org?.slug || "A2A Cloud user"}</strong>
          {needsSignIn && signInHref ? <a href={signInHref}>Sign in to run</a> : null}
        </div>
      </section>

      <form className="workspace" onSubmit={runComparison}>
        <section className="card input-card">
          <div className="row-between">
            <h2>1. Quote inputs</h2>
            <button type="button" onClick={() => { const f = successFixture(); setComparisonId(f.comparison_id); setQuotes(f.quotes); setWeights(f.weights); setDocuments([]); }}>
              Load fixture
            </button>
          </div>

          <label>
            Comparison ID
            <input value={comparisonId} onChange={(event) => setComparisonId(event.target.value)} />
          </label>

          <div className="upload-box">
            <label htmlFor="quote-file">Upload CSV/JSON instead</label>
            <input id="quote-file" type="file" accept=".csv,.json,text/csv,text/plain,application/json" multiple onChange={onFilesSelected} />
            <small>Browser bridge sends bounded base64 JSON; API clients can use typed FileUpload.</small>
            {documents.length ? <p>{documents.length} file(s) ready. Manual quote rows will be ignored for this run.</p> : null}
          </div>

          <div className="quotes-list">
            {quotes.map((quote, index) => (
              <fieldset key={index}>
                <legend>Quote {index + 1}</legend>
                <label>Vendor<input value={quote.vendor} onChange={(e) => setQuote(index, "vendor", e.target.value)} /></label>
                <label>Unit price<input type="number" step="0.01" value={quote.unit_price} onChange={(e) => setQuote(index, "unit_price", e.target.value)} /></label>
                <label>Quantity<input type="number" value={quote.quantity} onChange={(e) => setQuote(index, "quantity", e.target.value)} /></label>
                <label>Delivery days<input type="number" value={quote.delivery_days} onChange={(e) => setQuote(index, "delivery_days", e.target.value)} /></label>
                <label>Warranty months<input type="number" value={quote.warranty_months} onChange={(e) => setQuote(index, "warranty_months", e.target.value)} /></label>
              </fieldset>
            ))}
          </div>
          <div className="button-row">
            <button type="button" onClick={() => setQuotes((items) => [...items, { ...emptyQuote }])}>Add quote</button>
            <button type="button" onClick={() => setQuotes((items) => items.slice(0, Math.max(2, items.length - 1)))}>Remove last</button>
          </div>
        </section>

        <section className="card weight-card">
          <h2>2. Weights</h2>
          {Object.keys(weights).map((key) => (
            <label className="slider" key={key}>
              <span>{key} ({weights[key]})</span>
              <input type="range" min="0" max="100" value={weights[key]} onChange={(e) => setWeights((w) => ({ ...w, [key]: Number(e.target.value) }))} />
            </label>
          ))}
          <p className={totalWeight > 0 ? "hint" : "error-text"}>Total weight: {totalWeight}</p>
          <button disabled={running || needsSignIn} type="submit">{running ? "Running..." : "Compare and save"}</button>
          <button disabled={running || needsSignIn} type="button" onClick={() => reloadComparison()}>Reopen saved result</button>
          {error ? <p className="error-text" role="alert">{error}</p> : null}
        </section>
      </form>

      <section className="results-grid">
        <article className="card result-card">
          <h2>Recommendation</h2>
          {!result ? <p className="empty">No result yet. Run the fixture to produce the acceptance receipt.</p> : (
            <>
              <div className="winner">
                <span>Winner</span>
                <strong>{result.recommendation?.vendor}</strong>
              </div>
              <p>{result.recommendation?.rationale}</p>
              <dl>
                <div><dt>Score</dt><dd>{result.recommendation?.score}</dd></div>
                <div><dt>Total</dt><dd>{result.recommendation?.total_price}</dd></div>
                <div><dt>Delivery</dt><dd>{result.recommendation?.delivery_days} days</dd></div>
                <div><dt>Warranty</dt><dd>{result.recommendation?.warranty_months} months</dd></div>
              </dl>
              <h3>Ranked quotes</h3>
              <ol>
                {(result.ranked_quotes || []).map((quote) => <li key={quote.vendor}>{quote.vendor}: {quote.score} pts</li>)}
              </ol>
              <h3>Execution receipt</h3>
              <code>{result.execution_receipt?.payload_sha256 || "persisted by gateway/runtime"}</code>
            </>
          )}
        </article>

        <aside className="card history-card">
          <h2>Recent reopen list</h2>
          {history.length === 0 ? <p className="empty">Saved comparisons appear here after a run or reload.</p> : history.map((item) => (
            <button type="button" key={item.comparison_id} onClick={() => reloadComparison(item.comparison_id)}>
              <span>{item.comparison_id}</span>
              <strong>{item.recommendation?.vendor}</strong>
            </button>
          ))}
          <details>
            <summary>Live backend contract</summary>
            <pre>{JSON.stringify((config.skills || []).map((skill) => ({ name: skill.name, input_schema: skill.input_schema })), null, 2)}</pre>
          </details>
        </aside>
      </section>
    </main>
  );
}
