// screens-import.jsx — Excel / CSV import (Phase 2).
// REAL backend parsing: the file (xlsx / xls / csv / tsv / txt) is sent to
// /api/contacts/import-file, which parses it server-side, detects columns
// (phone, name, person, email, website, Google Maps, country, city), validates
// + normalizes phones and flags duplicates. We preview that result, let the
// operator drop rows, then commit via /api/contacts/import-commit. No fake UI.
const { useState } = React;
const IMP_STEPS = ["Source", "Review", "Analyze", "Done"];
// Analysis channels offered as part of import. Website + Maps are REAL (wired to the
// async job queues). Social discovery has no backend yet → shown as an honest, disabled
// "coming soon" channel (never a fake animation), per the no-fake-UI contract.
const IMPORT_ANALYZE_CHANNELS = [
  // `fields` mirror what the REAL analyzers actually extract (shown as badges when a
  // channel is selected) — honest, no fabricated promises.
  { id: "website", label: "Website analysis", icon: "globe", real: true, desc: "Detect platform, niche, design quality, weaknesses and the best Maxab service to pitch.",
    fields: ["Platform (Shopify / Salla / Zid / WooCommerce / Custom)", "Business niche & categories", "Pricing signals", "Design quality", "SEO & trust signals", "Main weaknesses", "Recommended service", "Sales talking points"] },
  { id: "maps", label: "Google Maps profile", icon: "mapPin", real: true, desc: "Pull rating, reviews, category and customer sentiment from the Google Maps listing.",
    fields: ["Business name & category", "Rating & review count", "Address & opening hours", "Customer sentiment", "Common review keywords", "Sales opportunity"] },
  { id: "social", label: "Social media discovery", icon: "users", real: false, desc: "Instagram / TikTok / Snapchat / LinkedIn discovery — coming soon (not yet connected)." },
];
const SOURCES = [
  { id: "file", label: "Excel or CSV file", desc: ".xlsx · .xls · .csv · .tsv", icon: "sheet" },
  { id: "paste", label: "Paste rows", desc: "phone, name, website, maps…", icon: "clipboard" },
];

// Read a (possibly binary) file as base64 — works for xlsx/xls and text alike.
function readBase64(file) {
  return new Promise((resolve, reject) => {
    const r = new FileReader();
    r.onload = () => { const s = String(r.result || ""); resolve(s.slice(s.indexOf(",") + 1)); };
    r.onerror = () => reject(new Error("Could not read that file."));
    r.readAsDataURL(file);
  });
}
// UTF-8-safe base64 of pasted text (handles Arabic).
function textToBase64(text) { return btoa(unescape(encodeURIComponent(String(text || "")))); }

const IMP_STATUS = {
  valid: { tone: "green", dot: "#22C55E", label: "Ready" },
  duplicate: { tone: "orange", dot: "#EA580C", label: "Duplicate" },
  invalid: { tone: "red", dot: "#B91C1C", label: "Invalid" },
};

function host(u) { return String(u || "").replace(/^https?:\/\//, "").split("/")[0]; }

function ImpStepper({ step }) {
  return (
    <div className="stepper">
      {IMP_STEPS.map((s, i) => (
        <React.Fragment key={s}>
          <div className={"step" + (i === step ? " is-active" : i < step ? " is-done" : "")}>
            <span className="step__num">{i < step ? <Icon name="check" size={15} /> : i + 1}</span>
            <span className="step__label" style={{ whiteSpace: "nowrap" }}>{s}</span>
          </div>
          {i < IMP_STEPS.length - 1 && <span className={"step__line" + (i < step ? " is-done" : "")} />}
        </React.Fragment>
      ))}
    </div>
  );
}

function PreviewRow({ row, onRemove }) {
  const m = IMP_STATUS[row.status] || IMP_STATUS.invalid;
  const dim = row.status !== "valid";
  return (
    <tr style={{ cursor: "default", background: dim ? "var(--bg-2)" : "transparent" }}>
      <td style={{ width: 200 }}>
        <div style={{ fontWeight: 600, fontSize: 13, fontFamily: "monospace", color: dim ? "var(--fg-3)" : "var(--fg-1)" }} dir="ltr">{row.phone || "—"}</div>
        {row.reason && <div style={{ fontSize: 11, color: "var(--color-danger)" }}>{row.reason}</div>}
      </td>
      <td style={{ color: row.name ? "var(--fg-1)" : "var(--fg-disabled)", fontSize: 13 }}>{row.name || "—"}</td>
      <td style={{ fontSize: 12 }}>
        <div className="col" style={{ gap: 2 }}>
          {row.website ? <span className="row" style={{ gap: 4, color: "var(--color-secondary)" }}><Icon name="globe" size={11} />{host(row.website)}</span> : null}
          {row.gmaps ? <span className="row" style={{ gap: 4, color: "var(--fg-4)" }}><Icon name="mapPin" size={11} />Maps</span> : null}
          {row.email ? <span className="row" style={{ gap: 4, color: "var(--fg-4)" }}><Icon name="mail" size={11} />{row.email}</span> : null}
          {!row.website && !row.gmaps && !row.email ? <span style={{ color: "var(--fg-disabled)" }}>—</span> : null}
        </div>
      </td>
      <td><Badge tone={m.tone} dot={m.dot}>{m.label}</Badge></td>
      <td style={{ textAlign: "end" }}>
        <button className="iconbtn" style={{ width: 32, height: 32, color: "var(--fg-4)" }} onClick={onRemove} title="Remove row"><Icon name="trash" size={15} /></button>
      </td>
    </tr>
  );
}

function ImportWizard({ onClose, onCreateCampaign }) {
  const [step, setStep] = useState(0);
  const [source, setSource] = useState("file");
  const [fileName, setFileName] = useState("");
  const [paste, setPaste] = useState("");
  const [rows, setRows] = useState([]);           // backend-tagged preview rows
  const [summary, setSummary] = useState(null);   // { total, valid, invalid, duplicate }
  const [includeDups, setIncludeDups] = useState(false);
  const [parseError, setParseError] = useState("");
  const [parsing, setParsing] = useState(false);
  const [importing, setImporting] = useState(false);
  const [result, setResult] = useState(null);     // { created, count, skipped }
  const [analyzeChannels, setAnalyzeChannels] = useState(["website", "maps"]); // selected REAL channels
  // Columns are auto-mapped server-side (detectColumns in /import-file). There is NO
  // manual mapping UI — `grid` is kept only as a truthiness flag for the non-interactive
  // "columns matched automatically" confirmation on the Review step.
  const [grid, setGrid] = useState(null);
  const fileRef = React.useRef(null);

  const apply = (preview) => {
    const r = (preview.rows || []).map((x, i) => ({ ...x, _key: i }));
    setRows(r); setSummary(preview.summary || null);
    if (preview.grid) setGrid(preview.grid);
    if (!r.length) setParseError("No rows found in that file. Check it has a phone column.");
  };

  const parseFile = async (file) => {
    if (!file) return;
    setParseError(""); setParsing(true); setFileName(file.name); setResult(null);
    try {
      const dataBase64 = await readBase64(file);
      apply(await API.contacts.importFile(file.name, dataBase64));
    } catch (e) {
      const msg = String(e.message || "");
      setParseError(/legacy_xls|415/.test(msg) ? "Legacy .xls isn't supported — open it and Save As .xlsx or CSV, then re-upload." : (msg || "Couldn't parse that file."));
      setRows([]); setSummary(null);
    } finally { setParsing(false); }
  };
  const parsePaste = async () => {
    if (!paste.trim()) return;
    setParseError(""); setParsing(true); setFileName("pasted rows"); setResult(null);
    try { apply(await API.contacts.importFile("pasted.csv", textToBase64(paste))); }
    catch (e) { setParseError(e.message || "Couldn't parse the pasted rows."); }
    finally { setParsing(false); }
  };

  const removeRow = (key) => setRows((rs) => rs.filter((r) => r._key !== key));
  const validRows = rows.filter((r) => r.status === "valid");
  const dupRows = rows.filter((r) => r.status === "duplicate");
  const invalidRows = rows.filter((r) => r.status === "invalid");
  const willImport = validRows.length + (includeDups ? dupRows.length : 0);

  const commit = async () => {
    setImporting(true); setParseError("");
    try {
      // send the surviving rows; backend re-validates + de-dupes authoritatively
      const send = rows.filter((r) => r.status === "valid" || (includeDups && r.status === "duplicate"))
        // carry the DETECTED platform / category / source too — dropping them here made
        // every imported lead show platform "Unknown" even when the sheet had it (which
        // breaks service recommendation, agent routing and the intelligence framing).
        .map((r) => ({ phone: r.phone, name: r.name, person: r.person, email: r.email, website: r.website, gmaps: r.gmaps, country: r.country, city: r.city, platform: r.platform, category: r.category, source: r.source }));
      // analyze = the operator-selected REAL channels (Analyze step) — controls which
      // background analysis jobs the backend queues for the imported leads.
      const r = await Actions.commitImport(send, { source: fileName ? `Import · ${fileName}` : "Import", includeDuplicates: includeDups, analyze: analyzeChannels });
      setResult(r); setStep(3);
    } catch (e) { setParseError(e.message || "Import failed."); }
    finally { setImporting(false); }
  };

  const importedGroup = result ? { id: "imported", name: "Just imported", count: result.count, contactIds: (result.created || []).map((c) => c.id), src: fileName || "Your upload", icon: "upload", fromImport: true } : null;

  return (
    <Scrim onClose={onClose}>
      <div className="modal" style={{ width: 880, maxWidth: "94vw", height: "86vh", maxHeight: 720, display: "flex", flexDirection: "column", padding: 0 }} onClick={(e) => e.stopPropagation()}>
        <div className="between" style={{ padding: "18px 24px", borderBottom: "1px solid var(--border-1)" }}>
          <div><div style={{ fontWeight: 800, fontSize: 16 }}>Import contacts</div><div style={{ fontSize: 12, color: "var(--fg-4)" }}>Step {step + 1} of {IMP_STEPS.length} · {IMP_STEPS[step]}</div></div>
          <button className="iconbtn" onClick={onClose}><Icon name="x" size={20} /></button>
        </div>
        <div style={{ padding: "16px 24px", borderBottom: "1px solid var(--border-1)", background: "var(--bg-2)" }}><ImpStepper step={step} /></div>

        <div style={{ flex: 1, overflowY: "auto", padding: 28 }}>
          {step === 0 && (
            <div className="fade-up">
              <h5 style={{ marginBottom: 4 }}>Upload your contacts</h5>
              <p className="muted" style={{ fontSize: 14, marginBottom: 20 }}>Excel (.xlsx) or CSV. We detect phone, name, website, Google Maps, email, city and country automatically. Phone is the only required column.</p>
              <div className="grid" style={{ gridTemplateColumns: "1fr 1fr", gap: 12, marginBottom: 20 }}>
                {SOURCES.map((s) => (
                  <button key={s.id} className={"optcard" + (source === s.id ? " is-selected" : "")} onClick={() => { setSource(s.id); setFileName(""); setRows([]); setSummary(null); setParseError(""); }}>
                    <span className="optcard__icon" style={{ background: "var(--bg-2)", color: "var(--color-secondary)" }}><Icon name={s.icon} size={20} /></span>
                    <div style={{ flex: 1 }}><div className="between"><b style={{ fontSize: 14 }}>{s.label}</b>{source === s.id && <Icon name="checkcircle" size={18} style={{ color: "var(--color-secondary)" }} />}</div><div style={{ fontSize: 12, color: "var(--fg-4)", marginTop: 3 }}>{s.desc}</div></div>
                  </button>
                ))}
              </div>
              {source === "paste" ? (
                <Field label="Paste rows (CSV — first line can be a header: phone,name,website,maps,email,city)">
                  <textarea className="textarea" rows={6} dir="auto" placeholder={"phone,name,website,maps\n+9665XXXXXXXX,Store or company name,store-website.com,\n+9665XXXXXXXX,Another store,,https://maps.google.com/?cid=..."} value={paste} onChange={(e) => setPaste(e.target.value)} />
                  <div className="row" style={{ gap: 8, marginTop: 8 }}>
                    <Button variant="dark" size="sm" icon="check" disabled={!paste.trim() || parsing} onClick={parsePaste}>{parsing ? "Parsing…" : "Parse rows"}</Button>
                    {rows.length > 0 && <span className="subtle" style={{ fontSize: 12 }}>{rows.length} rows detected</span>}
                  </div>
                </Field>
              ) : (
                <>
                  <input ref={fileRef} type="file" accept=".csv,.tsv,.txt,.xlsx,.xls,text/csv,text/plain,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" style={{ display: "none" }} onChange={(e) => parseFile(e.target.files && e.target.files[0])} />
                  <button onClick={() => fileRef.current && fileRef.current.click()} disabled={parsing}
                    style={{ width: "100%", border: "2px dashed " + (rows.length ? "var(--color-secondary)" : "var(--border-2)"), borderRadius: 16, padding: "36px 20px", background: rows.length ? "var(--color-primary-tint-soft)" : "var(--bg-2)", textAlign: "center", color: "var(--fg-3)" }}>
                    {parsing ? <><span className="spin" style={{ width: 30, height: 30 }} /><div style={{ fontWeight: 700, color: "var(--fg-1)", marginTop: 10 }}>Parsing {fileName}…</div></>
                      : rows.length ? <><Icon name="checkcircle" size={32} style={{ color: "var(--color-secondary)" }} /><div style={{ fontWeight: 700, color: "var(--fg-1)", marginTop: 10 }}>{fileName}</div><div style={{ fontSize: 12, marginTop: 4 }}>{rows.length} rows detected · click Continue</div></>
                        : <><Icon name="upload" size={32} /><div style={{ fontWeight: 700, color: "var(--fg-1)", marginTop: 10 }}>Click to browse a file</div><div style={{ fontSize: 12, marginTop: 4 }}>.xlsx · .xls · .csv · .tsv · .txt</div></>}
                  </button>
                </>
              )}
              {parseError && <div className="row" style={{ gap: 10, marginTop: 14, background: "var(--color-danger-soft)", color: "var(--color-danger)", borderRadius: 12, padding: "12px 14px", fontSize: 13 }}><Icon name="alert" size={16} />{parseError}</div>}
            </div>
          )}

          {step === 1 && (
            <div className="fade-up">
              <h5 style={{ marginBottom: 4 }}>Review the import</h5>
              <p className="muted" style={{ fontSize: 14, marginBottom: 16 }}>Phones are normalized to international format. Duplicates (already in your contacts or repeated in the file) and invalid rows are flagged.</p>
              {summary && (
                <div className="row wrap" style={{ gap: 10, marginBottom: 14 }}>
                  <div className="row" style={{ gap: 8, padding: "10px 14px", background: "var(--color-success-soft)", borderRadius: 12, fontSize: 13, fontWeight: 600 }}><Icon name="checkcircle" size={16} style={{ color: "var(--color-success)" }} />{validRows.length} ready</div>
                  {dupRows.length > 0 && <div className="row" style={{ gap: 8, padding: "10px 14px", background: "var(--color-orange-soft)", borderRadius: 12, fontSize: 13, fontWeight: 600 }}><Icon name="copy" size={16} style={{ color: "var(--color-orange)" }} />{dupRows.length} duplicate{dupRows.length === 1 ? "" : "s"}</div>}
                  {invalidRows.length > 0 && <div className="row" style={{ gap: 8, padding: "10px 14px", background: "var(--color-danger-soft)", borderRadius: 12, fontSize: 13, fontWeight: 600 }}><Icon name="alert" size={16} style={{ color: "var(--color-danger)" }} />{invalidRows.length} invalid</div>}
                </div>
              )}
              {/* Columns are mapped AUTOMATICALLY (server-side detectColumns) — no manual
                  mapping step, no selectors. This is a non-interactive confirmation only,
                  per the design: the operator never manages column mapping. */}
              {grid && (
                <div className="row" style={{ gap: 8, marginBottom: 14, padding: "10px 14px", background: "var(--color-primary-tint-soft)", border: "1px solid var(--color-primary-tint)", borderRadius: 12, fontSize: 12.5, color: "var(--fg-2)" }}>
                  <Icon name="sparkles" size={15} style={{ color: "var(--color-secondary)" }} />
                  <span>Columns matched automatically — phone, name, website, Google Maps, category and source detected for you.</span>
                </div>
              )}
              {dupRows.length > 0 && (
                <label className="row" style={{ gap: 8, marginBottom: 12, fontSize: 13, cursor: "pointer" }}>
                  <input type="checkbox" checked={includeDups} onChange={(e) => setIncludeDups(e.target.checked)} />
                  Also import the {dupRows.length} duplicate{dupRows.length === 1 ? "" : "s"} (off by default — we keep your existing records)
                </label>
              )}
              <Card flush>
                <div style={{ maxHeight: "44vh", overflowY: "auto" }}>
                  <table className="table">
                    <thead><tr><th>Phone</th><th>Name</th><th>Signals</th><th>Status</th><th></th></tr></thead>
                    <tbody>{rows.map((r) => <PreviewRow key={r._key} row={r} onRemove={() => removeRow(r._key)} />)}</tbody>
                  </table>
                </div>
              </Card>
              {parseError && <div className="row" style={{ gap: 10, marginTop: 12, background: "var(--color-danger-soft)", color: "var(--color-danger)", borderRadius: 12, padding: "12px 14px", fontSize: 13 }}><Icon name="alert" size={16} />{parseError}</div>}
            </div>
          )}

          {/* Step 2 — Analyze (choose which intelligence to auto-run after import) */}
          {step === 2 && (() => {
            const withWebsite = validRows.filter((r) => r.website).length + (includeDups ? dupRows.filter((r) => r.website).length : 0);
            const withMaps = validRows.filter((r) => r.gmaps).length + (includeDups ? dupRows.filter((r) => r.gmaps).length : 0);
            const countFor = (id) => id === "website" ? withWebsite : id === "maps" ? withMaps : 0;
            return (
              <div className="fade-up">
                <h5 style={{ marginBottom: 4 }}>Analyze as part of import</h5>
                <p className="muted" style={{ fontSize: 14, marginBottom: 20 }}>Choose what to analyze automatically after importing. It runs in the background — results land in each contact's intelligence panel.</p>
                <div className="col" style={{ gap: 12, marginBottom: 18 }}>
                  {IMPORT_ANALYZE_CHANNELS.map((ch) => {
                    const on = ch.real && analyzeChannels.includes(ch.id);
                    const n = countFor(ch.id);
                    return (
                      <div key={ch.id} onClick={() => ch.real && setAnalyzeChannels((cs) => cs.includes(ch.id) ? cs.filter((c) => c !== ch.id) : [...cs, ch.id])}
                        style={{ border: "1.5px solid " + (on ? "var(--color-secondary)" : "var(--border-2)"), borderRadius: "var(--radius-md)", padding: 16, background: on ? "var(--color-primary-tint-soft)" : "#fff", cursor: ch.real ? "pointer" : "default", opacity: ch.real ? 1 : 0.6 }}>
                        <div className="between">
                          <div className="row" style={{ gap: 12 }}>
                            <span className="opp" style={{ width: 40, height: 40, borderRadius: 12, background: on ? "var(--color-primary)" : "var(--bg-2)", color: on ? "var(--color-secondary)" : "var(--fg-3)", flexShrink: 0 }}><Icon name={ch.icon} size={20} /></span>
                            <div>
                              <div className="row" style={{ gap: 8 }}><span style={{ fontWeight: 700, fontSize: 14 }}>{ch.label}</span>{ch.real ? (n > 0 ? <Badge tone="neutral">{n} with data</Badge> : <Badge tone="neutral">none in this batch</Badge>) : <Badge tone="orange">Coming soon</Badge>}</div>
                              <div style={{ fontSize: 12.5, color: "var(--fg-4)", marginTop: 2 }}>{ch.desc}</div>
                            </div>
                          </div>
                          {ch.real
                            ? <span style={{ width: 22, height: 22, borderRadius: 999, border: "2px solid " + (on ? "var(--color-secondary)" : "var(--border-2)"), background: on ? "var(--color-secondary)" : "#fff", display: "inline-flex", alignItems: "center", justifyContent: "center", color: "#fff", flexShrink: 0 }}>{on && <Icon name="check" size={14} />}</span>
                            : <span title="Not yet connected" style={{ fontSize: 11.5, color: "var(--fg-disabled)", flexShrink: 0 }}>disabled</span>}
                        </div>
                        {on && ch.fields && (
                          <div className="row wrap" style={{ gap: 6, paddingInlineStart: 52, marginTop: 12 }}>
                            {ch.fields.map((f, i) => <Badge key={i} tone="neutral" style={{ fontSize: 11 }}>{f}</Badge>)}
                          </div>
                        )}
                      </div>
                    );
                  })}
                </div>
                <div className="between" style={{ gap: 8, padding: "12px 16px", background: "var(--color-primary-tint-soft)", border: "1px solid var(--color-primary-tint)", borderRadius: "var(--radius-md)", fontSize: 13, color: "var(--fg-2)" }}>
                  <span className="row" style={{ gap: 8 }}>
                    <Icon name="sparkles" size={16} style={{ color: "var(--color-secondary)", flexShrink: 0 }} />
                    {analyzeChannels.length > 0
                      ? <span>After import we'll queue <b>{analyzeChannels.includes("website") ? withWebsite : 0}</b> website + <b>{analyzeChannels.includes("maps") ? withMaps : 0}</b> Maps analysis job{(withWebsite + withMaps) === 1 ? "" : "s"} (real, background — no fabricated data).</span>
                      : <span>No analysis selected — contacts import without intelligence. You can analyze later from each contact or the Contacts toolbar.</span>}
                  </span>
                  {(() => { const realIds = IMPORT_ANALYZE_CHANNELS.filter((c) => c.real).map((c) => c.id); const allOn = realIds.every((id) => analyzeChannels.includes(id)); return <button className="btn btn--subtle btn--sm" style={{ flexShrink: 0 }} onClick={() => setAnalyzeChannels(allOn ? [] : realIds)}>{allOn ? "Deselect all" : "Select all"}</button>; })()}
                </div>
              </div>
            );
          })()}

          {step === 3 && result && (
            <div className="fade-up" style={{ textAlign: "center", padding: "24px 0" }}>
              <span className="opp" style={{ width: 76, height: 76, borderRadius: 22, background: "var(--color-primary)", color: "var(--color-secondary)", margin: "0 auto 20px" }}><Icon name="checkcircle" size={36} /></span>
              <h4 style={{ marginBottom: 8 }}>{result.count} contact{result.count === 1 ? "" : "s"} imported</h4>
              <p className="muted" style={{ fontSize: 14, maxWidth: 460, margin: "0 auto 20px" }}>They're in Contacts now{result.skipped ? ` · ${result.skipped} skipped (duplicate/invalid)` : ""}.{(result.websiteJobsQueued || result.mapsJobsQueued) ? ` Queued ${result.websiteJobsQueued || 0} website + ${result.mapsJobsQueued || 0} Maps analysis job${(result.websiteJobsQueued + result.mapsJobsQueued) === 1 ? "" : "s"} — results appear in each contact's intelligence panel.` : " No background analysis was selected."}</p>
              <div className="row" style={{ gap: 10, justifyContent: "center" }}>
                <Button variant="ghost" onClick={onClose}>View in Contacts</Button>
                {result.count > 0 && <Button variant="primary" icon="megaphone" onClick={() => onCreateCampaign && onCreateCampaign(importedGroup)}>Create campaign on these {result.count}</Button>}
              </div>
            </div>
          )}
        </div>

        {step < 3 && (
          <div className="between" style={{ padding: "16px 24px", borderTop: "1px solid var(--border-1)" }}>
            <button className="btn btn--ghost" onClick={() => step === 0 ? onClose() : setStep(step - 1)}><Icon name="chevronLeft" size={18} />{step === 0 ? "Cancel" : "Back"}</button>
            <div className="row" style={{ gap: 10 }}>
              {step === 1 && <span className="subtle" style={{ fontSize: 12 }}>{willImport} will import</span>}
              {step === 2 && <span className="subtle" style={{ fontSize: 12 }}>{willImport} contact{willImport === 1 ? "" : "s"} · {analyzeChannels.length} channel{analyzeChannels.length === 1 ? "" : "s"}</span>}
              {step === 0 && <Button variant="dark" disabled={!rows.length || parsing} onClick={() => setStep(1)} iconEnd="chevronRight">Continue</Button>}
              {step === 1 && <Button variant="dark" disabled={willImport === 0} onClick={() => setStep(2)} iconEnd="chevronRight">Continue</Button>}
              {step === 2 && <Button variant="dark" disabled={willImport === 0 || importing} onClick={commit} icon="sparkles">{importing ? "Importing…" : analyzeChannels.length ? `Import + Analyze ${willImport}` : `Import ${willImport}`}</Button>}
            </div>
          </div>
        )}
      </div>
    </Scrim>
  );
}

window.ImportWizard = ImportWizard;
