// dashboard-accountpicker-reusable-compone.js — extracted verbatim from dashboard.js (pure move).

// ── AccountPicker (reusable component) ─────────────────────────────
// Renders chip-style multi-select per platform, scoped to the platforms the
// op declares. Returns selected accountIds (per-platform map), validation, and
// a re-render hook the caller can use to refresh after selection changes.
//
// Usage:
//   const picker = await renderAccountPicker({
//     platforms: ["twitter", "linkedin"],
//     accountMode: "multi",      // "multi" | "single"
//     onChange: (selected) => { ... },
//     initial: { twitter: [12, 14], linkedin: [3] },
//   });
//   container.appendChild(picker.node);
//   picker.getSelected();        // → { twitter: [12, 14], linkedin: [3] }
//   picker.validate();           // → { ok: true } | { ok: false, error: "..." }
async function renderAccountPicker({ platforms, accountMode = "multi", onChange, initial = {} }) {
  // Fetch accounts via the shared TTL cache (60s). buildSidebar populates
  // dashboardState.cache.accounts on init, so this usually hits the cache and
  // returns instantly. If a user just connected an account, the 60s TTL gives
  // them stale data briefly — acceptable for the picker.
  const accountsData = await apiCached("accounts-all").catch(() => ({}));

  // Map "email" to backend's "smtp" array.
  const platformKey = (p) => (p === "email" ? "smtp" : p);

  // Selected state — per-platform array of account IDs.
  const selected = {};
  for (const p of platforms) {
    selected[p] = Array.isArray(initial[p]) ? [...initial[p]] : [];
  }

  function fireChange() {
    if (typeof onChange === "function") onChange({ ...selected });
  }

  const node = el("div", { class: "op-account-picker" });

  function rebuild() {
    node.innerHTML = "";
    if (platforms.length === 0) {
      node.appendChild(
        el(
          "div",
          { class: "op-account-empty" },
          "This operation doesn't bind to a specific account.",
        ),
      );
      return;
    }
    for (const p of platforms) {
      const accounts = accountsData[platformKey(p)] || [];
      const section = el("div", { class: "op-account-section" });
      section.appendChild(
        el("div", { class: "op-account-section-header" }, [
          el("span", { class: "op-account-platform-name" }, OC_PLATFORM_LABEL[p] || p),
          el("span", { class: "op-account-count" }, `${accounts.length} connected`),
        ]),
      );
      if (accounts.length === 0) {
        section.appendChild(
          el("div", { class: "op-account-empty" }, [
            el("span", null, "No accounts connected. "),
            el(
              "a",
              {
                href: "#accounts",
                onclick: (e) => {
                  e.preventDefault();
                  navigate("accounts");
                },
              },
              "Connect →",
            ),
          ]),
        );
      } else {
        const chipRow = el("div", { class: "op-account-chips" });
        for (const a of accounts) {
          const id = a.id;
          const label = a.account_identifier
            ? `@${a.account_identifier}`
            : a.label || a.identifier || a.email || a.phone || `Account #${id}`;
          const dot =
            a.status === "active"
              ? "green"
              : a.status === "rate_limited"
                ? "yellow"
                : a.status === "logged_out" || a.status === "expired"
                  ? "gray"
                  : "red";
          const isSelected = selected[p].includes(id);
          chipRow.appendChild(
            el(
              "button",
              {
                type: "button",
                class: `op-account-chip${isSelected ? " selected" : ""}`,
                onclick: () => {
                  if (accountMode === "single") {
                    // Single mode: replace entire selection.
                    selected[p] = isSelected ? [] : [id];
                  } else {
                    // Multi mode: toggle.
                    if (isSelected) selected[p] = selected[p].filter((x) => x !== id);
                    else selected[p].push(id);
                  }
                  rebuild();
                  fireChange();
                },
              },
              [
                el("span", { class: `op-account-dot ${dot}` }),
                el("span", { class: "op-account-chip-label" }, label),
              ],
            ),
          );
        }
        section.appendChild(chipRow);
      }
      node.appendChild(section);
    }
  }
  rebuild();

  return {
    node,
    getSelected: () => ({ ...selected }),
    // Returns flat array of all selected IDs (cross-platform).
    getFlatIds: () => {
      const all = [];
      for (const p of platforms) all.push(...selected[p]);
      return all;
    },
    validate: () => {
      if (platforms.length === 0) return { ok: true };
      // Need at least one account from at least one platform the op uses.
      const totalSelected = platforms.reduce((s, p) => s + (selected[p].length || 0), 0);
      if (totalSelected === 0) return { ok: false, error: "Select at least one account." };
      if (accountMode === "single" && totalSelected > 1)
        return { ok: false, error: "Select exactly one account." };
      return { ok: true };
    },
  };
}

async function renderOperationDetail(params) {
  const op = findOperation(params.opId);
  if (!op) {
    showError(`Unknown operation: ${params.opId}`, () => navigate("operations"));
    return;
  }

  // Detail flow state.
  const state = {
    step: 1,
    accountIds: {}, // per-platform arrays
    config: {},
    name: "",
    prefillSource: null,
  };

  // Read prefill if present (set by CRM bulk action, ⌘K palette, etc.).
  try {
    const stored = await chrome.storage.local.get(["_operationPrefill"]);
    const pf = stored._operationPrefill;
    if (pf && pf.opId === op.id) {
      if (pf.accountIds) state.accountIds = { ...pf.accountIds };
      if (pf.config) state.config = { ...pf.config };
      if (pf.name) state.name = pf.name;
      if (pf.source) state.prefillSource = pf.source;
      await chrome.storage.local.remove(["_operationPrefill"]);
      logTelemetry("operations", "detail_prefilled", { opId: op.id, source: state.prefillSource });
    }
  } catch {
    /* ignore */
  }

  logTelemetry("operations", "detail_open", { opId: op.id });

  // For ops without a templateKey (i.e., they have a route to a dedicated page),
  // bypass the unified flow and just deep-link there. The Operations Center is
  // still the discovery surface, but the launch lives in the existing page.
  if (op.route && !op.templateKey) {
    navigate(op.route);
    return;
  }

  // For ops without a templateKey AND without a route, we have no way to
  // configure them — bail.
  if (!op.templateKey) {
    showError(`Operation ${op.id} has no implementation`, () => navigate("operations"));
    return;
  }

  // Auto-skip Step 1 when there's no real choice to make. Specifically: if the
  // op uses accounts and only ONE account is available across all its platforms,
  // pre-select it and jump to Configure. The user sees a "Using @account —
  // change" pill at the top of step 2 so they can still swap accounts. Skipped
  // when prefill already populated accountIds (CRM bulk action, etc.).
  if (
    op.accountMode !== "none" &&
    op.platforms.length > 0 &&
    state.step === 1 &&
    Object.keys(state.accountIds).length === 0
  ) {
    try {
      const accounts = await apiCached("accounts-all");
      const platformKey = (p) => (p === "email" ? "smtp" : p);
      let totalCount = 0;
      let onlyAccount = null;
      for (const p of op.platforms) {
        const list = accounts?.[platformKey(p)] || [];
        for (const a of list) {
          totalCount++;
          if (totalCount === 1) {
            const label = a.account_identifier
              ? `@${a.account_identifier}`
              : a.label || a.identifier || a.email || a.phone || `Account #${a.id}`;
            onlyAccount = { platform: p, id: a.id, label };
          }
          if (totalCount > 1) break;
        }
        if (totalCount > 1) break;
      }
      if (totalCount === 1 && onlyAccount) {
        state.accountIds = { [onlyAccount.platform]: [onlyAccount.id] };
        state.autoSelectedAccount = onlyAccount;
        state.step = 2;
        logTelemetry("operations", "detail_auto_skip_accounts", {
          opId: op.id,
          accountId: onlyAccount.id,
        });
      }
    } catch {
      /* fall through to manual step 1 */
    }
  }

  let picker = null;

  function render() {
    const stepDots = el(
      "div",
      { class: "wizard-steps" },
      [1, 2, 3].map((n) =>
        el(
          "div",
          {
            class: `wizard-step-dot${n === state.step ? " active" : ""}${n < state.step ? " done" : ""}`,
          },
          [
            el("span", { class: "wizard-step-num" }, String(n)),
            el("span", { class: "wizard-step-label" }, ["", "Accounts", "Configure", "Launch"][n]),
          ],
        ),
      ),
    );

    const banner = state.prefillSource
      ? el("div", { class: "wizard-prefill-banner" }, [
          el("span", null, `Prefilled from ${state.prefillSource}.`),
          el(
            "button",
            {
              class: "btn-link",
              type: "button",
              onclick: () => {
                state.prefillSource = null;
                render();
              },
            },
            "dismiss",
          ),
        ])
      : null;

    let body;
    if (state.step === 1) body = renderStepAccounts();
    else if (state.step === 2) body = renderStepConfigure();
    else body = renderStepLaunch();

    setContentNode(
      el("div", { class: "wizard operations-detail" }, [
        el("div", { class: "page-header" }, [
          el("div", {}, [
            el(
              "button",
              {
                type: "button",
                class: "btn btn-secondary btn-tiny",
                onclick: () => navigate("operations"),
              },
              "‹ Back to catalog",
            ),
            el(
              "div",
              { class: "page-title", style: "margin-top: 10px;" },
              `${op.icon} ${op.label}`,
            ),
            el("div", { class: "page-subtitle" }, op.description),
            el(
              "div",
              { class: "op-card-tags", style: "margin-top: 8px;" },
              op.tags.map((t) => el("span", { class: `op-tag op-tag-${t}` }, t)),
            ),
          ]),
        ]),
        stepDots,
        banner,
        body,
      ]),
    );
  }

  function renderStepAccounts() {
    const wrap = el("div", { class: "wizard-step-body" });

    // No-account ops (e.g., signal pursuit) skip this step.
    if (op.accountMode === "none" || op.platforms.length === 0) {
      state.step = 2;
      return el("div");
    }

    wrap.appendChild(
      el(
        "div",
        { class: "wizard-section-title" },
        `Choose accounts (${op.accountMode === "single" ? "pick one" : "pick one or more"})`,
      ),
    );

    const pickerWrap = el("div");
    // Skeleton placeholder so the user sees something while accounts-all
    // fetches. With apiCached the fetch is usually instant on warm cache,
    // but cold load (or post-interval) shows ~50-200ms of blank otherwise.
    const skeleton = el("div", { class: "op-account-picker", "aria-hidden": "true" }, [
      el("div", { class: "op-account-section" }, [
        el("div", { class: "skeleton skeleton-text w-40" }),
        el("div", { class: "skeleton skeleton-row", style: "height: 28px; margin-top: 8px;" }),
      ]),
      el("div", { class: "op-account-section" }, [
        el("div", { class: "skeleton skeleton-text w-40" }),
        el("div", { class: "skeleton skeleton-row", style: "height: 28px; margin-top: 8px;" }),
      ]),
    ]);
    pickerWrap.appendChild(skeleton);
    wrap.appendChild(pickerWrap);

    // Build picker async.
    renderAccountPicker({
      platforms: op.platforms,
      accountMode: op.accountMode,
      initial: state.accountIds,
    }).then((p) => {
      picker = p;
      // Replace skeleton with the real picker. Two-step (remove + append) so
      // we don't have a brief flash of both being visible.
      pickerWrap.replaceChildren(p.node);
    });

    wrap.appendChild(
      el("div", { class: "wizard-actions" }, [
        el(
          "button",
          { type: "button", class: "btn btn-secondary", onclick: () => navigate("operations") },
          "‹ Cancel",
        ),
        el(
          "button",
          {
            type: "button",
            class: "btn btn-primary",
            onclick: () => {
              if (picker) {
                const v = picker.validate();
                if (!v.ok) {
                  toast(v.error, "err");
                  return;
                }
                state.accountIds = picker.getSelected();
              }
              state.step = 2;
              render();
            },
          },
          "Continue ›",
        ),
      ]),
    );

    return wrap;
  }

  function renderStepConfigure() {
    const def = WORKFLOW_TYPES[op.templateKey];
    if (!def) return el("div", { class: "wizard-hint" }, `Missing template: ${op.templateKey}`);

    const fieldEls = [];
    for (const f of def.fields) {
      const id = `op-field-${f.key}`;
      const cur = state.config[f.key];
      fieldEls.push(
        el("div", { class: "wizard-field" }, [
          el(
            "label",
            { class: "wizard-label", for: id },
            f.label + (f.optional ? " (optional)" : ""),
          ),
          f.type === "select"
            ? el(
                "select",
                {
                  id,
                  class: "wizard-input",
                  onchange: (e) => {
                    state.config[f.key] = e.target.value;
                  },
                },
                f.options.map((o) =>
                  el("option", { value: o, selected: cur === o ? "selected" : null }, o),
                ),
              )
            : f.textarea
              ? el("textarea", {
                  id,
                  class: "wizard-textarea",
                  placeholder: f.placeholder || "",
                  value: cur != null ? String(cur) : "",
                  oninput: (e) => {
                    state.config[f.key] = e.target.value;
                  },
                })
              : el("input", {
                  id,
                  class: "wizard-input",
                  type: f.type || "text",
                  placeholder: f.placeholder || "",
                  value: cur != null ? String(cur) : "",
                  oninput: (e) => {
                    state.config[f.key] =
                      f.type === "number" ? parseInt(e.target.value) || 0 : e.target.value;
                  },
                }),
        ]),
      );
    }

    // "Using @account — change" pill, shown only when Step 1 was auto-skipped.
    // Lets the user back out of the auto-selection if they actually wanted to
    // pick a different (or additional) account. Clears autoSelectedAccount on
    // change so the pill disappears next render.
    const autoPill = state.autoSelectedAccount
      ? el("div", { class: "op-auto-account-pill" }, [
          el(
            "span",
            null,
            `Using ${state.autoSelectedAccount.label} (${OC_PLATFORM_LABEL[state.autoSelectedAccount.platform] || state.autoSelectedAccount.platform})`,
          ),
          el(
            "button",
            {
              type: "button",
              class: "btn-link",
              onclick: () => {
                state.autoSelectedAccount = null;
                state.accountIds = {};
                state.step = 1;
                render();
              },
            },
            "change",
          ),
        ])
      : null;

    return el("div", { class: "wizard-step-body" }, [
      autoPill,
      el("div", { class: "wizard-section-title" }, "Configure"),
      el("div", { class: "wizard-fields" }, fieldEls),
      el("div", { class: "wizard-actions" }, [
        el(
          "button",
          {
            type: "button",
            class: "btn btn-secondary",
            onclick: () => {
              state.step = 1;
              render();
            },
          },
          "‹ Back",
        ),
        el(
          "button",
          {
            type: "button",
            class: "btn btn-primary",
            onclick: () => {
              const missing = def.fields.filter((f) => !f.optional && !state.config[f.key]);
              if (missing.length > 0) {
                toast(`Required: ${missing.map((m) => m.label).join(", ")}`, "err");
                return;
              }
              state.step = 3;
              render();
            },
          },
          "Continue ›",
        ),
      ]),
    ]);
  }

  function renderStepLaunch() {
    const def = WORKFLOW_TYPES[op.templateKey];
    const flatAccountIds = Object.values(state.accountIds).flat();
    return el("div", { class: "wizard-step-body" }, [
      el("div", { class: "wizard-section-title" }, "Name & launch"),
      el("input", {
        class: "wizard-input",
        placeholder: `My ${op.label.toLowerCase()} run`,
        value: state.name,
        oninput: (e) => {
          state.name = e.target.value;
        },
      }),
      el("div", { class: "wizard-summary" }, [
        el("div", { class: "wizard-summary-title" }, "Summary"),
        el("div", { class: "wizard-summary-row" }, [
          el("span", { class: "wizard-summary-label" }, "Operation"),
          el("span", null, `${op.icon} ${op.label}`),
        ]),
        el("div", { class: "wizard-summary-row" }, [
          el("span", { class: "wizard-summary-label" }, "Accounts"),
          el(
            "span",
            null,
            flatAccountIds.length === 0
              ? "—"
              : Object.entries(state.accountIds)
                  .filter(([_, ids]) => ids.length > 0)
                  .map(([p, ids]) => `${OC_PLATFORM_LABEL[p] || p}: ${ids.length}`)
                  .join(" · "),
          ),
        ]),
        el("div", { class: "wizard-summary-row" }, [
          el("span", { class: "wizard-summary-label" }, "Config"),
          el(
            "span",
            { class: "muted small" },
            (def?.fields || []).map((f) => `${f.label}: ${state.config[f.key] ?? "—"}`).join(" · "),
          ),
        ]),
      ]),
      el("div", { class: "wizard-actions" }, [
        el(
          "button",
          {
            type: "button",
            class: "btn btn-secondary",
            onclick: () => {
              state.step = 2;
              render();
            },
          },
          "‹ Back",
        ),
        el(
          "button",
          { type: "button", class: "btn btn-primary", onclick: launchOperation },
          "Launch",
        ),
      ]),
    ]);
  }

  async function launchOperation() {
    const name = (state.name || "").trim();
    if (!name) {
      toast("Name required", "err");
      return;
    }
    const def = WORKFLOW_TYPES[op.templateKey];
    if (!def) {
      toast("No template", "err");
      return;
    }

    // Flatten accountIds for the API. Backend (Phase 3) will use this as a
    // per-workflow account pool override; for now it's persisted in config_json.
    const flatAccountIds = Object.values(state.accountIds).flat();

    logTelemetry("operations", "launch", { opId: op.id, accountCount: flatAccountIds.length });

    try {
      // group_amplification has its own endpoint.
      // apiMutate auto-invalidates campaigns-stats so the next render sees the new row.
      if (op.templateKey === "group_amplification") {
        const r = await apiMutate("group-campaign-create", {
          body: {
            name,
            promotionPitch: state.config.promotionPitch,
            mode: state.config.mode,
            dailyPostsPerAccount: state.config.dailyPostsPerAccount,
            dailyRepliesPerAccount: state.config.dailyRepliesPerAccount,
            accountIds: flatAccountIds,
          },
        });
        if (r?.ok) {
          toast(`Group campaign created`, "ok");
          navigate("campaigns");
        } else {
          toast(`${r?.error || "Failed"}`, "err");
        }
        return;
      }
      // All other templated ops go through workflow-create.
      // accountIds is sent for backend to store in config_json — Phase 3 will
      // add execution-engine awareness; today it's persisted but advisory.
      const r = await apiMutate("workflow-create", {
        body: { type: op.templateKey, name, config: state.config, accountIds: flatAccountIds },
      });
      if (r?.ok) {
        toast(`${op.label} created`, "ok");
        navigate(`workflow/${r.workflowId}`);
      } else {
        toast(`${r?.error || "Failed"}`, "err");
      }
    } catch (err) {
      toast(`${err.message || "Network error"}`, "err");
    }
  }

  render();
}

function campaignTypeCard(icon, title, desc, onclick) {
  return el(
    "div",
    {
      class: "card",
      style: "cursor: pointer; transition: border-color 120ms;",
      onclick,
      onmouseenter: (e) => {
        e.currentTarget.style.borderColor = "var(--accent)";
      },
      onmouseleave: (e) => {
        e.currentTarget.style.borderColor = "var(--border)";
      },
    },
    [
      el("div", { style: "font-size: 28px; margin-bottom: 8px;" }, icon),
      el("div", { class: "primary-cell", style: "font-size: 14px; margin-bottom: 4px;" }, title),
      el("div", { class: "muted small" }, desc),
    ],
  );
}
