const { useState, useMemo, useCallback } = React;

function CopyBtn({ value }) {
  const [done, setDone] = useState(false);
  if (!value) return null;
  return (
    <span className="copy" onClick={() => {
      navigator.clipboard.writeText(value).then(() => {
        setDone(true); setTimeout(() => setDone(false), 1200);
      });
    }}>{done ? "copied" : "copy"}</span>
  );
}

function Status({ kind, text }) {
  if (!text) return <div className="status" />;
  return <div className={"status " + (kind || "")}>{text}</div>;
}

/* ---------- JSON Formatter ---------- */
function JsonTool() {
  const [input, setInput] = useState('{"name":"Ahmed","skills":["JS","Python","C"],"active":true}');
  const [indent, setIndent] = useState(2);
  const result = useMemo(() => {
    if (!input.trim()) return { ok: true, out: "", msg: "" };
    try {
      const parsed = JSON.parse(input);
      return { ok: true, out: JSON.stringify(parsed, null, indent), msg: "Valid JSON" };
    } catch (e) {
      return { ok: false, out: "", msg: e.message };
    }
  }, [input, indent]);
  return (
    <div className="panel">
      <h2>JSON Formatter & Validator</h2>
      <p className="desc">Pretty-print, minify, and validate JSON. Everything runs locally in your browser.</p>
      <div className="grid2">
        <div>
          <label className="field">Input</label>
          <textarea value={input} onChange={e => setInput(e.target.value)} spellCheck="false" />
        </div>
        <div>
          <label className="field">Output <CopyBtn value={result.out} /></label>
          <textarea value={result.out} readOnly spellCheck="false" />
        </div>
      </div>
      <div className="row">
        <button className="btn" onClick={() => setIndent(2)}>Indent 2</button>
        <button className="btn ghost" onClick={() => setIndent(4)}>Indent 4</button>
        <button className="btn ghost" onClick={() => setIndent(0)}>Minify</button>
      </div>
      <Status kind={result.ok ? "ok" : "err"} text={result.msg} />
    </div>
  );
}

/* ---------- Base64 ---------- */
function Base64Tool() {
  const [text, setText] = useState("Hello, world");
  const [mode, setMode] = useState("encode");
  const result = useMemo(() => {
    try {
      if (!text) return { ok: true, out: "" };
      if (mode === "encode") return { ok: true, out: btoa(unescape(encodeURIComponent(text))) };
      return { ok: true, out: decodeURIComponent(escape(atob(text))) };
    } catch (e) {
      return { ok: false, out: "", msg: "Input is not valid Base64." };
    }
  }, [text, mode]);
  return (
    <div className="panel">
      <h2>Base64 Encoder & Decoder</h2>
      <p className="desc">Convert text to and from Base64, with full Unicode support.</p>
      <div className="row" style={{ marginTop: 0, marginBottom: 12 }}>
        <button className={"btn " + (mode === "encode" ? "" : "ghost")} onClick={() => setMode("encode")}>Encode</button>
        <button className={"btn " + (mode === "decode" ? "" : "ghost")} onClick={() => setMode("decode")}>Decode</button>
      </div>
      <label className="field">Input</label>
      <textarea value={text} onChange={e => setText(e.target.value)} spellCheck="false" />
      <label className="field" style={{ marginTop: 14 }}>Output <CopyBtn value={result.out} /></label>
      <div className="out">{result.out}</div>
      <Status kind={result.ok ? "" : "err"} text={result.msg} />
    </div>
  );
}

/* ---------- JWT Decoder ---------- */
function b64urlDecode(str) {
  str = str.replace(/-/g, "+").replace(/_/g, "/");
  while (str.length % 4) str += "=";
  return decodeURIComponent(escape(atob(str)));
}
function JwtTool() {
  const [token, setToken] = useState("");
  const parsed = useMemo(() => {
    if (!token.trim()) return null;
    const parts = token.trim().split(".");
    if (parts.length < 2) return { error: "A JWT has three parts separated by dots." };
    try {
      const header = JSON.parse(b64urlDecode(parts[0]));
      const payload = JSON.parse(b64urlDecode(parts[1]));
      return { header, payload };
    } catch (e) {
      return { error: "Could not decode this token." };
    }
  }, [token]);
  const expNote = useMemo(() => {
    if (!parsed || parsed.error || !parsed.payload.exp) return null;
    const when = new Date(parsed.payload.exp * 1000);
    const expired = when.getTime() < Date.now();
    return { when, expired };
  }, [parsed]);
  return (
    <div className="panel">
      <h2>JWT Decoder</h2>
      <p className="desc">Inspect the header and payload of a JSON Web Token. Decoding happens locally and the token never leaves your machine.</p>
      <label className="field">Token</label>
      <textarea value={token} onChange={e => setToken(e.target.value)} placeholder="paste a JWT here" spellCheck="false" style={{ minHeight: 90 }} />
      {parsed && parsed.error && <Status kind="err" text={parsed.error} />}
      {parsed && !parsed.error && (
        <div className="grid2" style={{ marginTop: 14 }}>
          <div>
            <label className="field">Header</label>
            <div className="out">{JSON.stringify(parsed.header, null, 2)}</div>
          </div>
          <div>
            <label className="field">Payload</label>
            <div className="out">{JSON.stringify(parsed.payload, null, 2)}</div>
          </div>
        </div>
      )}
      {expNote && (
        <Status kind={expNote.expired ? "err" : "ok"}
          text={(expNote.expired ? "Expired on " : "Expires on ") + expNote.when.toLocaleString()} />
      )}
    </div>
  );
}

/* ---------- URL Encode ---------- */
function UrlTool() {
  const [text, setText] = useState("https://example.com/search?q=olive oil & dates");
  const [mode, setMode] = useState("encode");
  const out = useMemo(() => {
    try {
      return mode === "encode" ? encodeURIComponent(text) : decodeURIComponent(text);
    } catch (e) { return "Invalid input for decoding."; }
  }, [text, mode]);
  return (
    <div className="panel">
      <h2>URL Encoder & Decoder</h2>
      <p className="desc">Percent-encode or decode text for safe use in URLs and query strings.</p>
      <div className="row" style={{ marginTop: 0, marginBottom: 12 }}>
        <button className={"btn " + (mode === "encode" ? "" : "ghost")} onClick={() => setMode("encode")}>Encode</button>
        <button className={"btn " + (mode === "decode" ? "" : "ghost")} onClick={() => setMode("decode")}>Decode</button>
      </div>
      <label className="field">Input</label>
      <textarea value={text} onChange={e => setText(e.target.value)} spellCheck="false" />
      <label className="field" style={{ marginTop: 14 }}>Output <CopyBtn value={out} /></label>
      <div className="out">{out}</div>
    </div>
  );
}

/* ---------- Hash ---------- */
function HashTool() {
  const [text, setText] = useState("");
  const [hashes, setHashes] = useState(null);
  const [busy, setBusy] = useState(false);
  const run = useCallback(async () => {
    setBusy(true);
    const enc = new TextEncoder().encode(text);
    const algos = ["SHA-1", "SHA-256", "SHA-512"];
    const out = {};
    for (const a of algos) {
      const buf = await crypto.subtle.digest(a, enc);
      out[a] = Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2, "0")).join("");
    }
    setHashes(out); setBusy(false);
  }, [text]);
  return (
    <div className="panel">
      <h2>Hash Generator</h2>
      <p className="desc">Generate SHA-1, SHA-256, and SHA-512 digests using the browser's native Web Crypto API.</p>
      <label className="field">Input</label>
      <textarea value={text} onChange={e => setText(e.target.value)} spellCheck="false" style={{ minHeight: 90 }} />
      <div className="row">
        <button className="btn" onClick={run} disabled={busy}>{busy ? "Hashing..." : "Generate"}</button>
      </div>
      {hashes && (
        <div style={{ marginTop: 14 }}>
          {Object.entries(hashes).map(([k, v]) => (
            <div key={k} style={{ marginBottom: 12 }}>
              <label className="field">{k} <CopyBtn value={v} /></label>
              <div className="out">{v}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/* ---------- UUID ---------- */
function UuidTool() {
  const [list, setList] = useState([]);
  const [count, setCount] = useState(5);
  const gen = useCallback(() => {
    const make = () => (crypto.randomUUID ? crypto.randomUUID()
      : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => {
          const r = crypto.getRandomValues(new Uint8Array(1))[0] % 16;
          const v = c === "x" ? r : (r & 0x3 | 0x8);
          return v.toString(16);
        }));
    setList(Array.from({ length: Math.max(1, Math.min(50, count)) }, make));
  }, [count]);
  return (
    <div className="panel">
      <h2>UUID Generator</h2>
      <p className="desc">Generate cryptographically random version 4 UUIDs in bulk.</p>
      <div className="row" style={{ marginTop: 0 }}>
        <input type="number" value={count} min="1" max="50" onChange={e => setCount(+e.target.value)} style={{ width: 90 }} />
        <button className="btn" onClick={gen}>Generate</button>
        <CopyBtn value={list.join("\n")} />
      </div>
      {list.length > 0 && <div className="out" style={{ marginTop: 14 }}>{list.join("\n")}</div>}
    </div>
  );
}

/* ---------- Timestamp ---------- */
function TimeTool() {
  const [unix, setUnix] = useState(Math.floor(Date.now() / 1000).toString());
  const [human, setHuman] = useState("");
  const fromUnix = useMemo(() => {
    const n = Number(unix);
    if (!unix || Number.isNaN(n)) return null;
    const ms = unix.length > 10 ? n : n * 1000;
    const d = new Date(ms);
    if (Number.isNaN(d.getTime())) return null;
    return { iso: d.toISOString(), local: d.toLocaleString(), utc: d.toUTCString() };
  }, [unix]);
  const fromHuman = useMemo(() => {
    if (!human.trim()) return null;
    const d = new Date(human);
    if (Number.isNaN(d.getTime())) return { error: "Could not parse that date." };
    return { unix: Math.floor(d.getTime() / 1000) };
  }, [human]);
  return (
    <div className="panel">
      <h2>Unix Timestamp Converter</h2>
      <p className="desc">Convert between Unix timestamps and human-readable dates, in both directions.</p>
      <div className="grid2">
        <div>
          <label className="field">Unix timestamp (s or ms)</label>
          <input type="text" value={unix} onChange={e => setUnix(e.target.value)} />
          <div className="row"><button className="btn ghost" onClick={() => setUnix(Math.floor(Date.now() / 1000).toString())}>Now</button></div>
          {fromUnix && (
            <div className="kv" style={{ marginTop: 12 }}>
              <span className="k">ISO 8601</span><span>{fromUnix.iso}</span>
              <span className="k">Local</span><span>{fromUnix.local}</span>
              <span className="k">UTC</span><span>{fromUnix.utc}</span>
            </div>
          )}
        </div>
        <div>
          <label className="field">Date string</label>
          <input type="text" value={human} placeholder="2026-06-25 14:30" onChange={e => setHuman(e.target.value)} />
          {fromHuman && fromHuman.error && <Status kind="err" text={fromHuman.error} />}
          {fromHuman && !fromHuman.error && (
            <div className="kv" style={{ marginTop: 12 }}>
              <span className="k">Unix (seconds)</span><span>{fromHuman.unix} <CopyBtn value={String(fromHuman.unix)} /></span>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

const TOOLS = [
  { id: "json", label: "JSON", comp: JsonTool },
  { id: "jwt", label: "JWT Decoder", comp: JwtTool },
  { id: "base64", label: "Base64", comp: Base64Tool },
  { id: "url", label: "URL Encode", comp: UrlTool },
  { id: "hash", label: "Hashing", comp: HashTool },
  { id: "uuid", label: "UUID", comp: UuidTool },
  { id: "time", label: "Timestamp", comp: TimeTool },
];

function App() {
  const [active, setActive] = useState("json");
  const Active = (TOOLS.find(t => t.id === active) || TOOLS[0]).comp;
  return (
    <div className="app">
      <header className="top">
        <div className="logo">{"</>"}</div>
        <div>
          <h1>DevToolbox</h1>
        </div>
      </header>
      <p className="tagline">A fast, private set of everyday developer tools. Nothing you type is ever sent anywhere, it all runs in your browser.</p>
      <div className="tabs">
        {TOOLS.map(t => (
          <button key={t.id} className={"tab " + (active === t.id ? "active" : "")} onClick={() => setActive(t.id)}>{t.label}</button>
        ))}
      </div>
      <Active />
      <footer>
        Built by <a href="https://github.com/Touka01">Ahmed Toukebri</a> · runs fully offline · no tracking
      </footer>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
