/* ═══════════════════════════════════════════════════════════════════
   FileManagerHub.jsx — the DUAL-PATH HUB (§5) for the File Manager.
   Renders a path-selector (Convert | Organize); each path is a
   WPSB.Wizard.run({...}) config built from the shared FileWizard steps.
   This is the P0b "Convert migrated to WizardShell + path-selector"
   deliverable + the P1 Organize path, sharing one engine + one step set.

   Convert  : Source -> Metadata -> Destination -> Review  (existing /convert/* endpoints)
   Organize : Source -> Metadata -> Batches    -> Review   (new /organize/* endpoints)

   onCommit replicates the proven ConvertTab upload->batch->overage logic
   (deferred atomic commit). Route is composed to the shape the server
   normalizeRoute() + plugin route_file() expect:
     { tier:'media_library', site_id, site_url, destination, folder_id?, category_ids?, tag_ids? }

   Load AFTER WizardRunner.jsx + FileWizardSteps.jsx (+ the main Icon set).
   FileManager.jsx renders window.WPSB.FileManagerHub.DualPathHub on its
   'convert' tab (falling back to the legacy ConvertTab if this isn't loaded).

   Pattern: IIFE, React.createElement (pure ASCII), CSS vars only.
   ═══════════════════════════════════════════════════════════════════ */
(function () {
  const { useState } = React;
  const h = React.createElement;
  const tx = (k, v, f) => (window.WPSB && window.WPSB.t) ? window.WPSB.t(k, v, f) : (f != null ? f : k);
  const Icon = window.Icon || function () { return h('span', { 'aria-hidden': true }); };

  function FW() { return window.WPSB && window.WPSB.FileWizard; }
  function WZ() { return window.WPSB && window.WPSB.Wizard; }

  /* compose the server route from a selected site + placement fragment */
  function composeRoute(site, placement) {
    const p = placement || { destination: 'media_library' };
    if (!site) return null;               // no site => download/Library only (server: route=null)
    return Object.assign({ tier: 'media_library', site_id: site.id, site_url: site.site_url }, p);
  }
  function optionsFromMeta(meta) {
    const m = meta || {};
    const anyGen = m.gen && Object.keys(m.gen).some(function (k) { return m.gen[k]; });
    return {
      naming_pattern: (m.rename && m.rename.enabled && m.rename.pattern) ? m.rename.pattern : null,
      ai_metadata: !!anyGen,
    };
  }
  // Per-file metadata override (MetadataStep Option 2) -> the op payload shape the API
  // merges over generated wp_fields (entered values win). `alt` -> `alt_text`; tags/keywords
  // -> arrays; empties dropped. Returns null when nothing was entered.
  function cleanOverride(ov) {
    if (!ov || typeof ov !== 'object') return null;
    const out = {};
    ['title', 'caption', 'description', 'seo_description'].forEach(function (k) { if (typeof ov[k] === 'string' && ov[k].trim()) out[k] = ov[k].trim(); });
    if (typeof ov.alt === 'string' && ov.alt.trim()) out.alt_text = ov.alt.trim();
    ['tags', 'keywords'].forEach(function (k) { if (typeof ov[k] === 'string' && ov[k].trim()) out[k] = ov[k].split(',').map(function (s) { return s.trim(); }).filter(Boolean); });
    return Object.keys(out).length ? out : null;
  }
  // Attach wp_fields_override to each staged file by its index in ctx.data.files.
  function attachOverrides(stagedList, meta) {
    const fields = (meta && meta.fields) || {};
    return (stagedList || []).map(function (s, i) {
      if (!s) return s;
      const ov = cleanOverride(fields[i]);
      return ov ? Object.assign({}, s, { wp_fields_override: ov }) : s;
    });
  }

  /* ── overage consent block, rendered inside Review when a 402 came back ── */
  function OverageNotice({ ctx }) {
    const ov = ctx.data.overage;
    if (!ov) return null;
    const NoticeCard = window.NoticeCard;
    const nDocs = (ov.overage_docs || '?');
    const usedN = (ov.used || 0);
    const allowN = (ov.allowance === -1 ? '\u221e' : ov.allowance);
    const lead = (ov.overage_docs === 1)
      ? tx('page.filemanager.hub.overage.needs_one', { n: nDocs, used: usedN, allowance: allowN }, 'This batch needs {n} document beyond your included allowance ({used}/{allowance} used). ')
      : tx('page.filemanager.hub.overage.needs_many', { n: nDocs, used: usedN, allowance: allowN }, 'This batch needs {n} documents beyond your included allowance ({used}/{allowance} used). ');
    const tail = ov.billing_active
      ? tx('page.filemanager.hub.overage.billed', { rate: (ov.overage_rate_usd || 0.05) }, 'Overage is billed at ${rate}/doc.')
      : tx('page.filemanager.hub.overage.dormant', null, 'Overage billing is dormant pre-launch \u2014 accepting will NOT charge yet.');
    const body = lead + tail;
    return h('div', { style: { marginTop: 'var(--sp-4)' } },
      NoticeCard ? h(NoticeCard, { accent: 'var(--wiz-upsell, var(--beam))', icon: 'alert-triangle', title: tx('page.filemanager.hub.overage.title', null, 'Exceeds included allowance'), body: body, tag: tx('page.filemanager.hub.overage.tag', null, 'Action needed') }) : h('div', { style: { color: 'var(--text-2)', fontSize: '.84rem' } }, body),
      h('label', { style: { display: 'flex', alignItems: 'center', gap: 8, marginTop: 10, fontSize: '.84rem', color: 'var(--text)', cursor: 'pointer' } },
        h('input', { type: 'checkbox', checked: !!ctx.data.acceptOverage, onChange: function (e) { ctx.patch({ acceptOverage: e.target.checked }); } }),
        tx('page.filemanager.hub.overage.accept', null, 'Accept overage and proceed')
      )
    );
  }

  /* ════════════════════════ CONVERT CONFIG ════════════════════════ */
  function convertConfig({ presets, onBatchCreated, goLibrary, onExit }) {
    const fw = FW();
    return {
      id: 'fm_convert',
      eyebrow: tx('page.filemanager.hub.eyebrow', null, 'File Manager'),
      title: tx('page.filemanager.hub.convert.title', null, 'Convert documents'),
      subtitle: tx('page.filemanager.hub.convert.subtitle', null, 'Turn Office documents into accessible, tagged PDFs \u2014 then optionally route them into a connected WordPress site.'),
      stepVariant: 'vertical',
      initialData: { files: [], meta: { rename: { enabled: false, pattern: '' }, gen: {} }, route: { destination: 'media_library' } },
      finishLabel: tx('page.filemanager.hub.convert.finish', null, 'Convert & queue'),
      onExit: onExit,
      steps: [
        { key: 'source', title: tx('page.filemanager.hub.convert.source.title', null, 'Add documents'), subtitle: tx('page.filemanager.hub.convert.source.subtitle', null, 'Office files to convert'),
          validate: function (c) { return (c.data.files && c.data.files.length) ? true : tx('page.filemanager.hub.convert.source.validate', null, 'Add at least one document to convert.'); },
          render: function (c) { return h(fw.SourceStep, { ctx: c, multiple: true, label: tx('page.filemanager.hub.convert.source.dropzone', null, 'Drop documents here or click to browse'), hint: tx('page.filemanager.hub.convert.source.hint', null, 'DOCX, PPTX, XLSX, ODT, RTF, TXT, CSV \u2014 converted to tagged PDF') }); } },
        { key: 'meta', title: tx('page.filemanager.hub.convert.meta.title', null, 'Naming & metadata'), subtitle: tx('page.filemanager.hub.meta.optional', null, 'Optional'),
          render: function (c) { return h(fw.MetadataStep, { ctx: c, presets: presets }); } },
        { key: 'dest', title: tx('page.filemanager.hub.convert.dest.title', null, 'Destination'), subtitle: tx('page.filemanager.hub.convert.dest.subtitle', null, 'Where it lands'),
          render: function (c) { return h(fw.DestinationStep, { ctx: c }); } },
        { key: 'review', title: tx('page.filemanager.hub.review.title', null, 'Review & run'), subtitle: tx('page.filemanager.hub.review.subtitle', null, 'Confirm'),
          finishLabel: tx('page.filemanager.hub.convert.finish', null, 'Convert & queue'),
          render: function (c) { return h(fw.ReviewStep, { ctx: c, extraSummary: function (cc) { return h(OverageNotice, { ctx: cc }); } }); } },
      ],
      onCommit: async function (data, helpers) {
        const files = data.files || [];
        if (!files.length) throw new Error(tx('page.filemanager.hub.convert.err.no_files', null, 'Add at least one document.'));
        const api = fw.makeApi();
        let staged, batch_id;
        try {
          const r = await fw.uploadAndStage(api, '/convert/uploads', files, function (i, frac, total) { helpers.patch({ _progress: { i: i, frac: frac, total: total } }); });
          staged = r.staged; batch_id = r.batch_id;
        } catch (e) { throw new Error(e.message || tx('page.filemanager.hub.err.upload_failed', null, 'Upload failed.')); }
        const route = composeRoute(data.site, data.route);
        const body = { batch_id: batch_id, files: attachOverrides(staged, data.meta), route: route, options: optionsFromMeta(data.meta) };
        if (data.acceptOverage) body.accept_overage = true;
        const res = await api('/convert/batch', { method: 'POST', body: body });
        if (!res.ok) {
          if (res.status === 402 && res.code === 'DOCOPS_OVERAGE_CONSENT_REQUIRED' && res.data) {
            helpers.patch({ overage: res.data });
            throw new Error(tx('page.filemanager.hub.convert.err.overage', null, 'This batch exceeds your included allowance. Review the overage below, then choose Finish again to proceed.'));
          }
          throw new Error(res.error || tx('page.filemanager.hub.convert.err.enqueue', null, 'Could not enqueue conversion.'));
        }
        onBatchCreated && onBatchCreated({ batch_id: batch_id, created_at: new Date().toISOString(), count: files.length, mode: res.data.mode || 'convert_only' });
        helpers.toast((files.length === 1)
          ? tx('page.filemanager.hub.convert.toast_one', { n: files.length }, 'Conversion queued \u2014 {n} file')
          : tx('page.filemanager.hub.convert.toast_many', { n: files.length }, 'Conversion queued \u2014 {n} files'), 'ok');
        goLibrary && goLibrary();
        return { ok: true, batch_id: batch_id };
      },
    };
  }

  /* ════════════════════════ ORGANIZE CONFIG ═══════════════════════ */
  function organizeConfig({ presets, onBatchCreated, goLibrary, onExit }) {
    const fw = FW();
    return {
      id: 'fm_organize',
      eyebrow: tx('page.filemanager.hub.eyebrow', null, 'File Manager'),
      title: tx('page.filemanager.hub.organize.title', null, 'Organize & route media'),
      subtitle: tx('page.filemanager.hub.organize.subtitle', null, 'Bulk-upload any media, set metadata, and route each batch to a WordPress site \u2014 no conversion. Each batch goes to one destination.'),
      stepVariant: 'vertical',
      initialData: { files: [], meta: { rename: { enabled: false, pattern: '' }, gen: {} }, batches: null },
      finishLabel: tx('page.filemanager.hub.organize.finish', null, 'Upload & route'),
      onExit: onExit,
      steps: [
        { key: 'source', title: tx('page.filemanager.hub.organize.source.title', null, 'Add media'), subtitle: tx('page.filemanager.hub.organize.source.subtitle', null, 'Any allowed type'),
          validate: function (c) { return (c.data.files && c.data.files.length) ? true : tx('page.filemanager.hub.organize.source.validate', null, 'Add at least one file.'); },
          render: function (c) { return h(fw.SourceStep, { ctx: c, multiple: true, label: tx('page.filemanager.hub.organize.source.dropzone', null, 'Drop media here or click to browse'), hint: tx('page.filemanager.hub.organize.source.hint', null, 'Images, PDFs, docs, audio/video \u2014 uploaded as-is (no conversion)') }); } },
        { key: 'meta', title: tx('page.filemanager.hub.organize.meta.title', null, 'Metadata'), subtitle: tx('page.filemanager.hub.meta.optional', null, 'Optional'),
          render: function (c) { return h(fw.MetadataStep, { ctx: c, presets: presets }); } },
        { key: 'batches', title: tx('page.filemanager.hub.organize.batches.title', null, 'Destinations'), subtitle: tx('page.filemanager.hub.organize.batches.subtitle', null, 'Per batch'),
          validate: function (c) {
            const files = c.data.files || [];
            const batches = c.data.batches;
            if (!batches || !batches.length) return true; // default single-batch covers all
            const assigned = new Set(); batches.forEach(function (b) { (b.fileIdx || []).forEach(function (i) { assigned.add(i); }); });
            return assigned.size === files.length ? true : tx('page.filemanager.hub.organize.batches.validate', null, 'Every file must be assigned to a batch.');
          },
          render: function (c) { return h(fw.BatchBoard, { ctx: c }); } },
        { key: 'review', title: tx('page.filemanager.hub.review.title', null, 'Review & run'), subtitle: tx('page.filemanager.hub.review.subtitle', null, 'Confirm'),
          finishLabel: tx('page.filemanager.hub.organize.finish', null, 'Upload & route'),
          render: function (c) { return h(fw.ReviewStep, { ctx: c }); } },
      ],
      onCommit: async function (data, helpers) {
        const files = data.files || [];
        if (!files.length) throw new Error(tx('page.filemanager.hub.organize.err.no_files', null, 'Add at least one file.'));
        const api = fw.makeApi();
        let staged, batch_id;
        try {
          const r = await fw.uploadAndStage(api, '/organize/uploads', files, function (i, frac, total) { helpers.patch({ _progress: { i: i, frac: frac, total: total } }); });
          staged = r.staged; batch_id = r.batch_id;
        } catch (e) { throw new Error(e.message || tx('page.filemanager.hub.err.upload_failed', null, 'Upload failed.')); }
        let batches = data.batches;
        if (!batches || !batches.length) batches = [{ id: 'b1', name: tx('page.filemanager.hub.organize.batch_default_name', null, 'Batch 1'), fileIdx: files.map(function (_, i) { return i; }), site: null, route: { destination: 'media_library' } }];
        const meta = data.meta || {};
        const payloadBatches = batches.filter(function (b) { return (b.fileIdx || []).length; }).map(function (b) {
          return {
            name: b.name,
            route: composeRoute(b.site, b.route),
            metadata: meta,
            files: b.fileIdx.map(function (i) {
              const s = staged[i];
              if (!s) return null;
              const ov = cleanOverride(meta.fields && meta.fields[i]);
              return ov ? Object.assign({}, s, { wp_fields_override: ov }) : s;
            }).filter(Boolean),
          };
        });
        if (!payloadBatches.length) throw new Error(tx('page.filemanager.hub.organize.err.none_assigned', null, 'No files assigned to any batch.'));
        const res = await api('/organize/batch', { method: 'POST', body: { upload_batch_id: batch_id, batches: payloadBatches } });
        if (!res.ok) {
          if (res.code === 'OPTYPE_PENDING') throw new Error(tx('page.filemanager.hub.organize.err.optype_pending', null, 'Organize routing is not enabled on the server yet (apply the asset_import migration). Files were uploaded but not queued.'));
          if (res.code === 'PLAN_UPGRADE_REQUIRED') throw new Error(res.error || tx('page.filemanager.hub.organize.err.plan_upgrade', null, 'Bulk Organize is a Starter plan feature. Upgrade to unlock it.'));
          if (res.code === 'QUOTA_EXCEEDED' || res.code === 'PAYMENT_FAILED' || res.code === 'SUBSCRIPTION_INACTIVE' || res.code === 'SUBSCRIPTION_CHECK_UNAVAILABLE') {
            var gErr = res.error || tx('page.filemanager.hub.organize.err.ai_unavailable', null, 'AI metadata generation is unavailable right now.');
            var gHint = res.data && res.data.hint;
            throw new Error(gHint ? (gErr + ' ' + gHint) : gErr);
          }
          throw new Error(res.error || tx('page.filemanager.hub.organize.err.enqueue', null, 'Could not enqueue organize batches.'));
        }
        onBatchCreated && onBatchCreated({ batch_id: batch_id, created_at: new Date().toISOString(), count: files.length, mode: 'organize' });
        var mg = res.data && res.data.meta_gen;
        var genNote = '';
        if (mg && mg.requested) {
          var bits = [];
          if (mg.generated) bits.push(tx('page.filemanager.hub.organize.gen_generated', { n: mg.generated }, '{n} generated'));
          if (mg.skipped_quota) bits.push(tx('page.filemanager.hub.organize.gen_over_ai_limit', { n: mg.skipped_quota }, '{n} over your AI limit'));
          if (mg.skipped_cap) bits.push(tx('page.filemanager.hub.organize.gen_over_run_limit', { n: mg.skipped_cap }, '{n} over the per-run limit'));
          if (mg.failed) bits.push(tx('page.filemanager.hub.organize.gen_failed', { n: mg.failed }, '{n} could not be generated'));
          genNote = bits.length ? tx('page.filemanager.hub.organize.gen_prefix', { list: bits.join(', ') }, ' \u00b7 metadata: {list}') : '';
        }
        var filePhrase = (files.length === 1)
          ? tx('page.filemanager.hub.organize.toast_files_one', { n: files.length }, '{n} file')
          : tx('page.filemanager.hub.organize.toast_files_many', { n: files.length }, '{n} files');
        var batchPhrase = (payloadBatches.length === 1)
          ? tx('page.filemanager.hub.organize.toast_batches_one', { n: payloadBatches.length }, '{n} batch')
          : tx('page.filemanager.hub.organize.toast_batches_many', { n: payloadBatches.length }, '{n} batches');
        helpers.toast(tx('page.filemanager.hub.organize.toast', { files: filePhrase, batches: batchPhrase, note: genNote }, 'Organize queued \u2014 {files} across {batches}{note}'), 'ok');
        goLibrary && goLibrary();
        return { ok: true, batch_id: batch_id, batches: res.data.batches, meta_gen: mg || null };
      },
    };
  }

  /* ════════════════════════ PATH SELECTOR CARD ════════════════════ */
  function PathCard({ icon, title, desc, points, onPick }) {
    const [hover, setHover] = useState(false);
    return h('button', {
      type: 'button', onClick: onPick,
      onMouseEnter: function () { setHover(true); }, onMouseLeave: function () { setHover(false); },
      style: {
        textAlign: 'left', cursor: 'pointer', flex: '1 1 280px', minWidth: 260,
        background: hover ? 'var(--wiz-card-hover, var(--surface-2))' : 'var(--surface)',
        border: '1px solid ' + (hover ? 'var(--beam)' : 'var(--border)'),
        boxShadow: hover ? '0 0 0 3px color-mix(in oklch, var(--beam) 14%, transparent)' : 'none',
        borderRadius: 'var(--r-xl, 16px)', padding: 'var(--sp-6, 24px)', display: 'flex', flexDirection: 'column', gap: 12,
        transition: 'border-color 150ms ease, box-shadow 150ms ease, background 150ms ease',
      },
    },
      h('div', { style: { display: 'flex', alignItems: 'center', gap: 12 } },
        h('span', { style: { width: 44, height: 44, borderRadius: 'var(--r, 10px)', background: 'var(--beam-dim)', color: 'var(--beam)', display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 'none' } }, h(Icon, { name: icon, size: 22 })),
        h('span', { style: { fontWeight: 'var(--fw-label, 600)', fontSize: '1.05rem', color: 'var(--text)' } }, title)
      ),
      h('p', { style: { margin: 0, fontSize: '.86rem', lineHeight: 1.5, color: 'var(--text-2)' } }, desc),
      h('ul', { style: { margin: 0, paddingLeft: 18, display: 'flex', flexDirection: 'column', gap: 4 } },
        points.map(function (p, i) { return h('li', { key: i, style: { fontSize: '.8rem', color: 'var(--muted)' } }, p); })),
      h('span', { style: { marginTop: 4, display: 'inline-flex', alignItems: 'center', gap: 6, color: 'var(--beam)', fontSize: '.82rem', fontWeight: 'var(--fw-medium, 500)' } }, tx('page.filemanager.hub.pathcard.start', null, 'Start'), h(Icon, { name: 'arrow-right', size: 14 }))
    );
  }

  /* ════════════════════════ THE HUB ═══════════════════════════════ */
  function DualPathHub({ presets, onBatchCreated, goLibrary }) {
    const [path, setPath] = useState(null);   // null | 'convert' | 'organize'
    const wz = WZ(); const fw = FW();

    if (!wz || !wz.run || !fw) {
      return h('div', { style: { padding: 'var(--sp-6, 24px)', color: 'var(--text-2)', fontSize: '.9rem' } },
        tx('page.filemanager.hub.engine_loading', null, 'The wizard engine is still loading. If this persists, confirm WizardRunner.jsx + FileWizardSteps.jsx are loaded before FileManagerHub.jsx.'));
    }

    if (!path) {
      return h('div', { style: { display: 'flex', flexDirection: 'column', gap: 'var(--sp-5, 20px)' } },
        h('div', null,
          h('div', { className: 'wiz-eyebrow', style: { marginBottom: 6 } }, tx('page.filemanager.hub.choose_eyebrow', null, 'Choose a workflow')),
          h('p', { style: { margin: 0, color: 'var(--text-2)', fontSize: '.9rem', maxWidth: 620, lineHeight: 1.5 } }, tx('page.filemanager.hub.choose_desc', null, 'Convert office documents into accessible PDFs, or bulk-upload and route any media into your WordPress sites \u2014 both share the same metadata, destination, and delivery steps.'))
        ),
        h('div', { style: { display: 'flex', gap: 'var(--sp-4, 16px)', flexWrap: 'wrap' } },
          h(PathCard, {
            icon: 'file-text', title: tx('page.filemanager.hub.card.convert.title', null, 'Convert'),
            desc: tx('page.filemanager.hub.card.convert.desc', null, 'Office documents \u2192 accessible, tagged PDFs, then route them into a site.'),
            points: [tx('page.filemanager.hub.card.convert.point1', null, 'DOCX / PPTX / XLSX / ODT / RTF / TXT / CSV'), tx('page.filemanager.hub.card.convert.point2', null, 'WCAG-tagged PDF output + accessibility audit'), tx('page.filemanager.hub.card.convert.point3', null, 'Optional naming + AI metadata')],
            onPick: function () { setPath('convert'); },
          }),
          h(PathCard, {
            icon: 'image', title: tx('page.filemanager.hub.card.organize.title', null, 'Organize'),
            desc: tx('page.filemanager.hub.card.organize.desc', null, 'Bulk-upload any media as-is and route each batch to one destination.'),
            points: [tx('page.filemanager.hub.card.organize.point1', null, 'Images, PDFs, docs, audio/video'), tx('page.filemanager.hub.card.organize.point2', null, 'Per-batch destination (one place per batch)'), tx('page.filemanager.hub.card.organize.point3', null, 'Rename + per-field metadata, no conversion')],
            onPick: function () { setPath('organize'); },
          })
        )
      );
    }

    const back = function () { setPath(null); };
    const cfg = path === 'convert'
      ? convertConfig({ presets: presets, onBatchCreated: onBatchCreated, goLibrary: goLibrary, onExit: back })
      : organizeConfig({ presets: presets, onBatchCreated: onBatchCreated, goLibrary: goLibrary, onExit: back });

    return h('div', null,
      h('button', { type: 'button', className: 'btn btn-ghost btn-sm', onClick: back, style: { marginBottom: 12 } }, h(Icon, { name: 'chevron-left', size: 12 }), tx('page.filemanager.hub.choose_different', null, 'Choose a different workflow')),
      wz.run(cfg)
    );
  }

  window.WPSB = window.WPSB || {};
  window.WPSB.FileManagerHub = { DualPathHub: DualPathHub, convertConfig: convertConfig, organizeConfig: organizeConfig };
  console.log('[WPSB FileManagerHub] Dual-path hub loaded (Convert + Organize wizard configs).');
})();
