// Wallets refuse to silently change the RPC URL of a network the user
// already added — if someone added this app's local/test network earlier
// (before the /rpc proxy existed, or with any other broken RPC URL), the
// wallet keeps using that stale endpoint forever regardless of what this app
// requests, and every chain call fails with an unhelpful low-level error.
// There is no programmatic fix for that (only the user's wallet UI can), so
// detect the pattern and tell them exactly what to do instead of showing the
// raw ethers error.
function describeChainError(e) {
  const raw = (e && e.message) || String(e);
  if (/too many errors|RPC endpoint|could not coalesce|could not detect network|SERVER_ERROR|-32002/i.test(raw)) {
    return (
      `Your wallet can't reach the network's RPC endpoint. This usually means the network was added to ` +
      `your wallet earlier with the wrong RPC URL and won't self-update. Open your wallet's network ` +
      `settings, remove (or edit) the network matching this app's chain, then try sealing again — it will ` +
      `be re-added with the correct address: ${window.location.origin}/rpc`
    );
  }
  return raw;
}

function Upload({ onNavigate }) {
  const { t } = useI18n();
  const { address, connect, chainConfig, getSigner, ensureContractNetwork } = useWallet();
  const [step, setStep] = React.useState(1);
  const [projectId, setProjectId] = React.useState(null);
  const [projectName, setProjectName] = React.useState('');
  const [projectDesc, setProjectDesc] = React.useState('');
  const [events, setEvents] = React.useState([]);
  const [chain, setChain] = React.useState('polygon');
  const [sealing, setSealing] = React.useState(false);
  const [sealed, setSealed] = React.useState(false);
  const [sealError, setSealError] = React.useState(null);
  const [finalHash, setFinalHash] = React.useState(null);
  const [txHash, setTxHash] = React.useState(null);
  const [step1Error, setStep1Error] = React.useState(null);
  const [creatingProject, setCreatingProject] = React.useState(false);

  function back() { setStep(s => Math.max(s - 1, 1)); }

  async function createProjectAndAdvance() {
    setStep1Error(null);
    setCreatingProject(true);
    try {
      const res = await fetch('/api/projects', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ title: projectName.trim(), subtitle: projectDesc.trim() }),
      });
      const body = await res.json();
      if (!res.ok) throw new Error(body.error || `Could not create the project (HTTP ${res.status}).`);
      setProjectId(body.id);
      setStep(2);
    } catch (e) {
      setStep1Error(e && e.message ? e.message : String(e));
    } finally {
      setCreatingProject(false);
    }
  }

  async function commit() {
    setSealError(null);
    if (chain !== 'polygon') {
      setSealError('Only Polygon (the network the contract is actually deployed to) is wired up right now — choose Polygon to seal for real.');
      return;
    }
    setSealing(true);
    try {
      await ensureContractNetwork();
      const root = window.merkleRoot(events.map((e) => e.hash));
      const signer = await getSigner();
      if (!signer) throw new Error('Connect a wallet before sealing.');
      const contract = new window.ethers.Contract(chainConfig.contractAddress, chainConfig.abi, signer);
      const tx = await contract.seal(root, window.ethers.toUtf8Bytes(projectId));
      const receipt = await tx.wait();

      const res = await fetch(`/api/projects/${projectId}/seal`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ chain, txHash: receipt.hash, merkleRoot: root }),
      });
      const body = await res.json();
      if (!res.ok) throw new Error(body.error || 'Server rejected the seal.');
      setFinalHash(body.finalHash);
      setTxHash(body.txHash);
      setSealed(true);
    } catch (e) {
      setSealError(describeChainError(e));
    } finally {
      setSealing(false);
    }
  }

  if (!address) {
    return (
      <div className="container py-48 text-center">
        <p className="ink-2 mb-24">{t('wallet.connectPrompt')}</p>
        <button className="btn btn-primary" onClick={connect}>{t('wallet.connect')}</button>
      </div>
    );
  }

  return (
    <div>
      <div className="container-narrow py-48">
        <div className="row gap-8 mb-24 tiny" style={{ textTransform:'none', letterSpacing:0.04 }}>
          <a onClick={() => onNavigate('dashboard')} style={{cursor:'pointer'}}>{t('common.dashboard')}</a>
          <span>›</span>
          <span className="ink-2">{t('upload.crumb')}</span>
        </div>

        <div className="mb-32">
          <div className="eyebrow mb-8">{t('upload.eyebrow')}</div>
          <h1 className="h2 serif">{t('upload.title')}</h1>
        </div>

        <Stepper step={step} />

        {step === 1 && (
          <Step1
            projectName={projectName}
            setProjectName={setProjectName}
            projectDesc={projectDesc}
            setProjectDesc={setProjectDesc}
            onNext={createProjectAndAdvance}
            submitting={creatingProject}
            error={step1Error}
          />
        )}
        {step === 2 && <Step2 projectId={projectId} events={events} setEvents={setEvents} onNext={() => setStep(3)} onBack={back} />}
        {step === 3 && <Step3 chain={chain} setChain={setChain} onNext={() => setStep(4)} onBack={back} events={events} />}
        {step === 4 && (
          <Step4
            sealing={sealing}
            sealed={sealed}
            sealError={sealError}
            finalHash={finalHash}
            txHash={txHash}
            onCommit={commit}
            chain={chain}
            onBack={back}
            onDone={() => onNavigate('project:' + projectId)}
            onNavigate={onNavigate}
            projectName={projectName}
            events={events}
          />
        )}
      </div>
    </div>
  );
}

function Stepper({ step }) {
  const { t } = useI18n();
  const steps = [t('upload.step.project'), t('upload.step.events'), t('upload.step.chain'), t('upload.step.seal')];
  return (
    <div className="stepper">
      {steps.map((s, i) => {
        const n = i + 1;
        const state = n < step ? 'done' : n === step ? 'active' : '';
        return (
          <React.Fragment key={s}>
            <div className={'stepper-item ' + state}>
              <span className="stepper-num">{n < step ? '✓' : n}</span>
              <span>{s}</span>
            </div>
            {i < steps.length - 1 && <div className="stepper-line" />}
          </React.Fragment>
        );
      })}
    </div>
  );
}

/* ===== STEP 1 ===== */
function Step1({ projectName, setProjectName, projectDesc, setProjectDesc, onNext, submitting, error }) {
  const { t } = useI18n();
  const canGo = projectName.trim().length > 0 && !submitting;
  const categories = t('upload.s1.categories');
  return (
    <div className="card" style={{ padding: 40 }}>
      <h3 className="h3 serif mb-8">{t('upload.s1.title')}</h3>
      <p className="ink-3 small mb-32">{t('upload.s1.hint')}</p>

      <div className="col gap-24">
        <div className="field">
          <label className="field-label">{t('upload.s1.field.title')}</label>
          <input className="input" placeholder={t('upload.s1.field.title.ph')} value={projectName} onChange={e => setProjectName(e.target.value)} />
        </div>
        <div className="field">
          <label className="field-label">{t('upload.s1.field.desc')}</label>
          <textarea className="textarea" placeholder={t('upload.s1.field.desc.ph')} value={projectDesc} onChange={e => setProjectDesc(e.target.value)} />
        </div>
        <div className="row gap-12">
          <div className="field" style={{ flex: 1 }}>
            <label className="field-label">{t('upload.s1.field.category')}</label>
            <select className="select">
              {(Array.isArray(categories) ? categories : []).map(c => <option key={c}>{c}</option>)}
            </select>
          </div>
        </div>
      </div>

      {error && (
        <div className="mt-24" style={{ padding: 16, borderRadius: 8, border: '1px solid var(--error)', color: 'var(--error)', fontSize: 13 }}>
          {error}
        </div>
      )}

      <div className="row between mt-32" style={{ paddingTop: 24, borderTop:'1px dashed var(--hairline)' }}>
        <div className="tiny" style={{ textTransform:'none', letterSpacing:0.04 }}>{t('common.step')} 1 {t('common.of')} 4</div>
        <button className="btn btn-primary" disabled={!canGo} onClick={onNext} style={{ opacity: canGo ? 1 : 0.4 }}>
          {submitting ? t('common.loading') : t('common.continue')} <IconArrowRight />
        </button>
      </div>
    </div>
  );
}

/* ===== STEP 2 ===== */
function Step2({ projectId, events, setEvents, onNext, onBack }) {
  const { t } = useI18n();
  const { getSigner } = useWallet();
  const [showAdd, setShowAdd] = React.useState(false);
  const [newKind, setNewKind] = React.useState('image');
  const [newLabel, setNewLabel] = React.useState('');
  const [file, setFile] = React.useState(null);
  const [hashing, setHashing] = React.useState(false);
  const [previewHash, setPreviewHash] = React.useState(null);
  const [addError, setAddError] = React.useState(null);
  const [dragOver, setDragOver] = React.useState(false);
  const fileInputRef = React.useRef(null);
  const kinds = t('upload.s2.kinds');

  function pickFile(f) {
    if (!f) return;
    setAddError(null);
    setFile(f);
    setShowAdd(true);
  }

  function handleDragOver(e) {
    e.preventDefault();
    e.stopPropagation();
    setDragOver(true);
  }
  function handleDragLeave(e) {
    e.preventDefault();
    e.stopPropagation();
    setDragOver(false);
  }
  function handleDrop(e) {
    e.preventDefault();
    e.stopPropagation();
    setDragOver(false);
    pickFile(e.dataTransfer.files && e.dataTransfer.files[0]);
  }

  async function addEvent() {
    if (!file) return;
    setAddError(null);
    setHashing(true);
    try {
      const signer = await getSigner();
      if (!signer) throw new Error('Connect a wallet before adding an event.');
      const { hash, signature } = await window.walletSignFile(file, signer);
      setPreviewHash(hash);
      const kindWho = ['prompt', 'image', 'video', 'audio'].includes(newKind) ? 'ai' : 'human';
      const res = await fetch(`/api/projects/${projectId}/events`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({
          kind: newKind,
          who: kindWho,
          label: newLabel || `${file.name}`,
          hash,
          signature,
          ts: new Date().toISOString(),
        }),
      });
      const body = await res.json();
      if (!res.ok) throw new Error(body.error || 'The server rejected this event.');
      setEvents(body.events);
      setNewLabel('');
      setFile(null);
      setShowAdd(false);
    } catch (e) {
      setAddError(e && e.message ? e.message : String(e));
    } finally {
      setHashing(false);
      setPreviewHash(null);
    }
  }

  async function removeEvent(eventId) {
    const res = await fetch(`/api/projects/${projectId}/events/${eventId}`, { method: 'DELETE', credentials: 'include' });
    const body = await res.json();
    setEvents(body.events);
  }

  return (
    <div className="col gap-24">
      <div className="card" style={{ padding: 40 }}>
        <div className="between mb-24">
          <div>
            <h3 className="h3 serif">{t('upload.s2.title')}</h3>
            <p className="ink-3 small mt-8">{t('upload.s2.hint')}</p>
          </div>
          <span className="tiny" style={{ textTransform:'none', letterSpacing:0.04 }}>{t('upload.s2.queued', { n: events.length })}</span>
        </div>

        <div className="col gap-8 mb-24">
          {events.map((e) => (
            <div key={e.id} className="card-flat" style={{ padding: 16 }}>
              <div className="row between" style={{ alignItems:'flex-start' }}>
                <EventBadge event={e} compact={true} />
                <button className="btn btn-ghost btn-sm" onClick={() => removeEvent(e.id)}>✕</button>
              </div>
              <div className="mt-8" style={{ paddingLeft: 52 }}>
                <span className="hash" style={{ fontSize:12 }}><ShortHash hash={e.hash} len={8} /></span>
              </div>
            </div>
          ))}
        </div>

        {!showAdd ? (
          <div
            className="dropzone"
            style={{ borderColor: dragOver ? 'var(--ink)' : undefined, background: dragOver ? 'var(--surface-soft)' : undefined }}
            onClick={() => setShowAdd(true)}
            onDragOver={handleDragOver}
            onDragLeave={handleDragLeave}
            onDrop={handleDrop}
          >
            <div className="serif" style={{ fontSize: 22 }}>{t('upload.s2.drop.title')}</div>
            <div className="small ink-3 mt-8">{t('upload.s2.drop.hint')}</div>
          </div>
        ) : (
          <div className="card" style={{ padding: 24, background:'var(--surface-soft)' }}>
            {hashing ? (
              <div className="col gap-12 text-center py-24">
                <div className="tiny">{t('upload.s2.hashing')}</div>
                <div className="hash-mono-lg" style={{ fontSize: 22 }}>
                  <ScrambleHash target={previewHash || window.makeHash(Date.now())} duration={1400} />
                </div>
                <div className="small ink-3">{t('upload.s2.hashingSub')}</div>
              </div>
            ) : (
              <div className="col gap-16">
                <div className="row gap-12">
                  <div className="field" style={{ flex: 1 }}>
                    <label className="field-label">{t('upload.s2.type')}</label>
                    <select className="select" value={newKind} onChange={e => setNewKind(e.target.value)}>
                      <option value="prompt">{kinds.prompt}</option>
                      <option value="reference">{kinds.reference}</option>
                      <option value="image">{kinds.image}</option>
                      <option value="video">{kinds.video}</option>
                      <option value="audio">{kinds.audio}</option>
                      <option value="edit">{kinds.edit}</option>
                      <option value="license">{kinds.license}</option>
                    </select>
                  </div>
                  <div className="field" style={{ flex: 2 }}>
                    <label className="field-label">{t('upload.s2.label')}</label>
                    <input className="input" placeholder={t('upload.s2.label.ph')} value={newLabel} onChange={e => setNewLabel(e.target.value)} />
                  </div>
                </div>
                <div
                  className="dropzone"
                  style={{ padding: 24, borderColor: dragOver ? 'var(--ink)' : undefined, background: dragOver ? 'var(--surface-soft)' : undefined }}
                  onClick={() => fileInputRef.current.click()}
                  onDragOver={handleDragOver}
                  onDragLeave={handleDragLeave}
                  onDrop={handleDrop}
                >
                  <input
                    ref={fileInputRef}
                    type="file"
                    style={{ display: 'none' }}
                    onChange={(e) => pickFile(e.target.files[0])}
                  />
                  <div className="small">{file ? file.name : t('upload.s2.smallDrop')}</div>
                  <div className="tiny mt-8" style={{ textTransform:'none', letterSpacing:0.04 }}>{t('upload.s2.smallDropHint')}</div>
                </div>
                {addError && (
                  <div style={{ padding: 12, borderRadius: 8, border: '1px solid var(--error)', color: 'var(--error)', fontSize: 13 }}>
                    {addError}
                  </div>
                )}
                <div className="row gap-8">
                  <button className="btn btn-primary" onClick={addEvent} disabled={!file} style={{ opacity: file ? 1 : 0.4 }}>{t('upload.s2.compute')}</button>
                  <button className="btn btn-ghost" onClick={() => { setShowAdd(false); setFile(null); setAddError(null); }}>{t('common.cancel')}</button>
                </div>
              </div>
            )}
          </div>
        )}
      </div>

      <div className="row between">
        <button className="btn btn-ghost" onClick={onBack}>← {t('common.back')}</button>
        <button className="btn btn-primary" onClick={onNext} disabled={!events.length} style={{ opacity: events.length ? 1 : 0.4 }}>
          {t('upload.s2.chooseChain')} <IconArrowRight />
        </button>
      </div>
    </div>
  );
}

/* ===== STEP 3 ===== */
function Step3({ chain, setChain, onNext, onBack, events }) {
  const { t } = useI18n();
  const chains = CHAIN_OPTIONS.map((c) => ({
    ...c,
    tag: t(`upload.s3.${c.key}Tag`),
    desc: t(`upload.s3.${c.key}Desc`),
  }));

  return (
    <div className="col gap-24">
      <div className="card" style={{ padding: 40 }}>
        <h3 className="h3 serif mb-8">{t('upload.s3.title')}</h3>
        <p className="ink-3 small mb-32">{t('upload.s3.hint')}</p>

        <div className="col gap-12">
          {chains.map(c => (
            <div
              key={c.id}
              className={c.enabled ? undefined : 'chain-option-soon'}
              onClick={c.enabled ? () => setChain(c.id) : undefined}
              aria-disabled={c.enabled ? undefined : true}
              title={c.enabled ? undefined : t('upload.s3.soonHint')}
              style={{
                padding: 24,
                borderRadius: 12,
                border: '1px solid ' + (chain === c.id ? 'var(--ink)' : 'var(--hairline)'),
                cursor: c.enabled ? 'pointer' : 'not-allowed',
                background: chain === c.id ? 'var(--surface-soft)' : 'var(--canvas)',
                transition: 'border 0.15s, background 0.15s',
              }}
            >
              <div className="between">
                <div>
                  <div className="row gap-12">
                    <div className="serif" style={{ fontSize: 24, letterSpacing:'-0.012em' }}>{c.name}</div>
                    <ChainBadge chain={c.id} />
                    {!c.enabled && <span className="badge badge-soon">{t('upload.s3.soon')}</span>}
                  </div>
                  <div className="small ink-3 mt-8">{c.desc}</div>
                </div>
                {c.enabled ? (
                  <div style={{ width: 20, height: 20, borderRadius:'50%', border: '1.5px solid ' + (chain === c.id ? 'var(--ink)' : 'var(--hairline)'), background: chain === c.id ? 'var(--ink)' : 'transparent', flexShrink: 0 }} />
                ) : (
                  <div style={{ width: 20, height: 20, flexShrink: 0 }} />
                )}
              </div>
              <div className="row gap-32 mt-16" style={{ paddingTop: 16, borderTop:'1px dashed var(--hairline)' }}>
                <div className="col gap-4"><div className="tiny">{t('upload.s3.estCost')}</div><div className="mono" style={{ fontSize: 14 }}>{c.cost}</div></div>
                <div className="col gap-4"><div className="tiny">{t('upload.s3.confirmation')}</div><div className="mono" style={{ fontSize: 14 }}>{c.speed}</div></div>
                <div className="col gap-4"><div className="tiny">{t('upload.s3.class')}</div><div className="mono" style={{ fontSize: 14 }}>{c.tag}</div></div>
              </div>
            </div>
          ))}
        </div>

        <div className="mt-32 card-flat" style={{ padding: 20 }}>
          <div className="tiny mb-8">{t('upload.s3.merkleSummary')}</div>
          <div className="row between">
            <div className="mono small">{t('upload.s3.leaves', { n: events.length })}</div>
            <div className="mono small ink-3">{t('upload.s3.payload', { b: events.length * 32 })}</div>
          </div>
        </div>
      </div>

      <div className="row between">
        <button className="btn btn-ghost" onClick={onBack}>← {t('common.back')}</button>
        <button className="btn btn-primary" onClick={onNext}>{t('upload.s3.reviewSeal')} <IconArrowRight /></button>
      </div>
    </div>
  );
}

// Only Polygon is actually wired up: ProofRegistry.sol is deployed there and
// server/src/chain.js verifies the Sealed log against that one contract. The
// rest are listed so the roadmap is visible, but they stay unselectable until
// a contract exists on them — offering a chain we can't verify would produce
// certificates that fail their own verification step.
const CHAIN_OPTIONS = [
  { id:'polygon',   key:'polygon', name:'Polygon',   cost:'≈ $0.02', speed:'≈ 3s',  enabled: true },
  { id:'ethereum',  key:'eth',     name:'Ethereum',  cost:'≈ $4.20', speed:'≈ 15s', enabled: false },
  { id:'avalanche', key:'avax',    name:'Avalanche', cost:'≈ $0.05', speed:'≈ 2s',  enabled: false },
  { id:'arbitrum',  key:'arb',     name:'Arbitrum',  cost:'≈ $0.03', speed:'≈ 1s',  enabled: false },
  { id:'base',      key:'base',    name:'Base',      cost:'≈ $0.01', speed:'≈ 2s',  enabled: false },
];

function chainDisplayName(id) {
  const c = CHAIN_OPTIONS.find((x) => x.id === id);
  return c ? c.name : id;
}

/* ===== STEP 4 ===== */
function Step4({ sealing, sealed, sealError, finalHash, txHash, onCommit, chain, onBack, onDone, onNavigate, projectName, events }) {
  const { t } = useI18n();
  const chainName = chainDisplayName(chain);

  if (sealed) {
    return (
      <div className="col gap-24">
        <div className="card" style={{ padding: 48, textAlign:'center' }}>
          <div style={{ display:'inline-flex', width: 88, height: 88, borderRadius:'50%', background:'var(--primary)', color:'var(--on-primary)', alignItems:'center', justifyContent:'center', marginBottom: 24, fontFamily:'var(--serif)', fontSize: 14 }}>
            {t('cert.sealed')}
          </div>
          <h3 className="h2 serif mb-16">{t('upload.s4.sealed', { chain: chainName })}</h3>
          <p className="ink-2 mb-32"><em className="italic serif">{projectName || t('upload.s4.noTitle')}</em> — {t('upload.s4.sealedSub')}</p>

          <div className="col gap-8 text-center mb-32">
            <div className="tiny">{t('upload.s4.finalRoot')}</div>
            <div className="hash-mono-lg" style={{ fontSize: 20 }}>{finalHash}</div>
          </div>

          <div className="row gap-12" style={{ justifyContent:'center' }}>
            <a
              className="btn btn-secondary"
              href={'#tx:' + txHash}
              onClick={(e) => { e.preventDefault(); onNavigate('tx:' + txHash); }}
            >
              {t('common.viewExplorer')}
            </a>
            <button className="btn btn-primary" onClick={onDone}>{t('upload.s4.backToDash')}</button>
          </div>
        </div>
      </div>
    );
  }

  if (sealing) {
    return (
      <div className="card" style={{ padding: 64, textAlign:'center' }}>
        <div className="eyebrow mb-24">{t('upload.s4.committing', { chain: chainName })}</div>
        <div className="hash-mono-lg mb-24" style={{ fontSize: 24 }}>
          <ScrambleHash target={window.makeHash(555)} duration={2200} />
        </div>
        <div className="small ink-3">{t('upload.s4.committingSub')}</div>
      </div>
    );
  }

  return (
    <div className="col gap-24">
      <div className="card" style={{ padding: 40 }}>
        <h3 className="h3 serif mb-8">{t('upload.s4.title')}</h3>
        <p className="ink-3 small mb-32">{t('upload.s4.hint')}</p>

        <div className="col gap-16">
          <ReviewRow label={t('upload.s4.row.project')}>{projectName || <span className="ink-3">{t('upload.s4.noTitle')}</span>}</ReviewRow>
          <ReviewRow label={t('upload.s4.row.events')}>{t('upload.s4.row.eventsVal', { n: events.length })}</ReviewRow>
          <ReviewRow label={t('upload.s4.row.chain')}><ChainBadge chain={chain} /></ReviewRow>
          <ReviewRow label={t('upload.s4.row.cert')}>{t('upload.s4.row.certVal')}</ReviewRow>
        </div>

        {/* Last screen before the wallet signs — say what chain this really is
            while the user can still back out. */}
        <div className="mt-24"><ChainNoticeInline variant="seal" /></div>

        {sealError && (
          <div className="mt-24" style={{ padding: 16, borderRadius: 8, border: '1px solid var(--error)', color: 'var(--error)', fontSize: 13 }}>
            {sealError}
          </div>
        )}
      </div>

      <div className="row between">
        <button className="btn btn-ghost" onClick={onBack}>← {t('common.back')}</button>
        <button className="btn btn-primary btn-lg" onClick={onCommit}>{t('upload.s4.sealCta', { chain: chainName })}</button>
      </div>
    </div>
  );
}

function ReviewRow({ label, children }) {
  return (
    <div className="row between" style={{ paddingBottom: 16, borderBottom: '1px dashed var(--hairline)' }}>
      <span className="tiny">{label}</span>
      <span style={{ fontSize: 14 }}>{children}</span>
    </div>
  );
}

window.Upload = Upload;
