/* ── HOSTING COST EDITOR ──────────────────────────────────────
   Editable cost knobs that flow into Plan Comparison margins and
   Recommended Hosting/Care cards. Two surfaces:

   1. Shared cost components — tooling bundle, care labor rate, civic
      cost ratio, care-only base/rate. These drive the default cost
      formula for every plan that doesn't have a per-plan override.

   2. Per-plan overrides — edit `charge/mo` or `cost/mo` for a specific
      plan. Overrides win over defaults.

   State persisted to localStorage under 'wpsb-hosting-costs'.
   Exposes a global `window.useHostingCosts()` hook + `calcPlanCost()`
   helper so HostingTab and the Estimator sidebar can share one source
   of truth for plan economics.
*/

const HOSTING_COSTS_KEY = 'wpsb-hosting-costs-v1';

const DEFAULT_COST_COMPONENTS = {
  // Shared — apply across non-civic, non-care plans
  toolingBundle:   8.26,   // $/mo — plugin licenses, monitoring, bundled tools
  careLaborPerMin: 0.50,   // $/min — blended labor rate for care support

  // Civic plans — approximated as a percentage of client charge
  civicCostRatio:  0.42,   // 42% cost ratio

  // Care-only plans (no hosting)
  careOnlyBase:    10.00,  // $/mo — base tooling for care-only
  careOnlyPerMin:  0.45,   // $/min — rate for care-only plans

  // Breakdown of what tooling bundle covers (informational — editable)
  toolingBreakdown: [
    { id: 'plugins',     label: 'Plugin licenses (bundled)', cost: 3.50 },
    { id: 'monitoring',  label: 'Uptime + error monitoring', cost: 1.75 },
    { id: 'termageddon', label: 'Termageddon privacy policy', cost: 1.50 },
    { id: 'backups',     label: 'Offsite backup storage',    cost: 0.75 },
    { id: 'security',    label: 'Security scanning (Patchstack/WPScan)', cost: 0.76 },
  ],
};

function loadHostingCosts() {
  try {
    const raw = localStorage.getItem(HOSTING_COSTS_KEY);
    if (!raw) return { components: { ...DEFAULT_COST_COMPONENTS }, overrides: {} };
    const parsed = JSON.parse(raw);
    return {
      components: { ...DEFAULT_COST_COMPONENTS, ...(parsed.components || {}) },
      overrides:  parsed.overrides || {},
    };
  } catch (e) {
    return { components: { ...DEFAULT_COST_COMPONENTS }, overrides: {} };
  }
}

function saveHostingCosts(state) {
  try { localStorage.setItem(HOSTING_COSTS_KEY, JSON.stringify(state)); } catch(e) {}
}

// Shared state singleton — so multiple components render the same values
// and a single save triggers a re-render everywhere.
let _hostingCostsState = loadHostingCosts();
const _hostingCostsSubs = new Set();
function _notify() { _hostingCostsSubs.forEach(fn => fn(_hostingCostsState)); }

window.useHostingCosts = function useHostingCosts() {
  const { useState, useEffect } = React;
  const [state, setState] = useState(_hostingCostsState);
  useEffect(() => {
    _hostingCostsSubs.add(setState);
    return () => _hostingCostsSubs.delete(setState);
  }, []);
  const update = (next) => {
    _hostingCostsState = typeof next === 'function' ? next(_hostingCostsState) : next;
    saveHostingCosts(_hostingCostsState);
    _notify();
  };
  return [state, update];
};

// Single source of truth for plan cost calculation.
// Usage: calcPlanCost(plan, hostTab)   where hostTab ∈ 'M'|'MWC'|'CIVIC'|'CARE'
window.calcPlanCost = function calcPlanCost(plan, hostTab) {
  const { components, overrides } = _hostingCostsState;
  const ov = overrides[plan.code];
  // Cost override always wins
  if (ov && typeof ov.cost === 'number') return Math.round(ov.cost * 100) / 100;

  if (hostTab === 'CARE') {
    const min = parseInt((plan.support || '0').match(/\d+/)?.[0] || '0', 10);
    return Math.round((min * components.careOnlyPerMin + components.careOnlyBase) * 100) / 100;
  }
  if (hostTab === 'CIVIC') {
    const charge = (ov && typeof ov.charge === 'number') ? ov.charge : plan.charge;
    return Math.round(charge * components.civicCostRatio * 100) / 100;
  }
  // M / MWC — hosting + tooling + care labor
  const hosting = plan.hosting || 0;
  const minMatch = (plan.support || '').match(/\d+/);
  const careMin  = minMatch ? parseInt(minMatch[0], 10) : 0;
  return Math.round(
    (hosting + components.toolingBundle + careMin * components.careLaborPerMin) * 100
  ) / 100;
};

// Effective charge — respects override
window.planCharge = function planCharge(plan) {
  const ov = _hostingCostsState.overrides[plan.code];
  return (ov && typeof ov.charge === 'number') ? ov.charge : plan.charge;
};

/* ── UI ────────────────────────────────────────────────────── */

function CostInput({ value, onChange, prefix = '$', suffix, step = 0.01, width = 92 }) {
  return (
    <div style={{ display:'inline-flex', alignItems:'center', background:'var(--surface-3)', border:'1px solid var(--border)', borderRadius:5, padding:'2px 6px', fontSize:'.76rem' }}>
      {prefix && <span style={{ color:'var(--dim)', marginRight:3 }}>{prefix}</span>}
      <input type="number" value={value} step={step} onChange={e => onChange(parseFloat(e.target.value) || 0)}
        style={{ background:'transparent', border:'none', color:'var(--text)', fontFamily:'var(--font-mono)', fontSize:'.76rem', width, outline:'none', padding:0 }}/>
      {suffix && <span style={{ color:'var(--dim)', marginLeft:3, fontSize:'.7rem' }}>{suffix}</span>}
    </div>
  );
}

function PercentInput({ value, onChange }) {
  return (
    <div style={{ display:'inline-flex', alignItems:'center', background:'var(--surface-3)', border:'1px solid var(--border)', borderRadius:5, padding:'2px 6px', fontSize:'.76rem' }}>
      <input type="number" value={(value * 100).toFixed(1)} step={0.5} min={0} max={100}
        onChange={e => onChange((parseFloat(e.target.value) || 0) / 100)}
        style={{ background:'transparent', border:'none', color:'var(--text)', fontFamily:'var(--font-mono)', fontSize:'.76rem', width:60, outline:'none', padding:0 }}/>
      <span style={{ color:'var(--dim)', marginLeft:3, fontSize:'.7rem' }}>%</span>
    </div>
  );
}

function HostingCostEditor() {
  const { useState, useMemo } = React;
  const [state, setState] = window.useHostingCosts();
  const [overrideTab, setOverrideTab] = useState('MWC');
  const [showOnly, setShowOnly] = useState('all'); // all | overridden

  const comp = state.components;
  const ov  = state.overrides;

  const CD_PLANS = window.CD_PLANS;
  const overridePlans = overrideTab === 'CARE' ? CD_PLANS.CARE_ONLY : CD_PLANS[overrideTab];

  function setComp(key, val) {
    setState(s => ({ ...s, components: { ...s.components, [key]: val } }));
  }
  function setBreakdown(id, cost) {
    setState(s => ({
      ...s,
      components: {
        ...s.components,
        toolingBreakdown: s.components.toolingBreakdown.map(b => b.id === id ? { ...b, cost } : b),
      },
    }));
  }
  function addBreakdownRow() {
    const id = 'custom-' + Date.now();
    setState(s => ({
      ...s,
      components: {
        ...s.components,
        toolingBreakdown: [...s.components.toolingBreakdown, { id, label: 'New component', cost: 0 }],
      },
    }));
  }
  function renameBreakdown(id, label) {
    setState(s => ({
      ...s,
      components: {
        ...s.components,
        toolingBreakdown: s.components.toolingBreakdown.map(b => b.id === id ? { ...b, label } : b),
      },
    }));
  }
  function removeBreakdown(id) {
    setState(s => ({
      ...s,
      components: {
        ...s.components,
        toolingBreakdown: s.components.toolingBreakdown.filter(b => b.id !== id),
      },
    }));
  }
  function setOverride(code, field, val) {
    setState(s => {
      const next = { ...s.overrides };
      if (val === '' || val == null || Number.isNaN(val)) {
        if (next[code]) {
          const copy = { ...next[code] };
          delete copy[field];
          if (Object.keys(copy).length === 0) delete next[code];
          else next[code] = copy;
        }
      } else {
        next[code] = { ...(next[code] || {}), [field]: val };
      }
      return { ...s, overrides: next };
    });
  }
  function clearAllOverrides() {
    if (!confirm('Clear all per-plan overrides? This resets charge/cost back to defaults.')) return;
    setState(s => ({ ...s, overrides: {} }));
  }
  function resetAll() {
    if (!confirm('Reset all cost components AND overrides to defaults?')) return;
    setState({ components: { ...DEFAULT_COST_COMPONENTS }, overrides: {} });
  }

  // Auto-sum the breakdown → tooling bundle (display only, not automatic)
  const breakdownTotal = useMemo(
    () => comp.toolingBreakdown.reduce((s, b) => s + (b.cost || 0), 0),
    [comp.toolingBreakdown]
  );
  const applyBreakdownTotal = () => setComp('toolingBundle', Math.round(breakdownTotal * 100) / 100);

  const overrideCount = Object.keys(ov).length;

  return (
    <div style={{ marginTop:16, display:'flex', flexDirection:'column', gap:14 }}>
      {/* Info banner */}
      <div className="box sa" style={{ padding:'10px 14px', display:'flex', alignItems:'flex-start', gap:10 }}>
        <Icon name="info" size={14}/>
        <div style={{ fontSize:'.82rem' }}>
          <strong>Internal cost editor.</strong> Adjust cost components and per-plan overrides here — changes flow live into the Plan Comparison margin table and the Recommended Hosting / Care cards on the Estimator tab. Saved per-browser; use Export to share with teammates.
        </div>
      </div>

      {/* Shared cost components */}
      <div className="grid" style={{ gridTemplateColumns:'1fr 1fr', gap:14 }}>
        {/* Left: formula knobs */}
        <div className="card">
          <div className="card-head">
            <h2 className="card-title"><span style={{ marginRight:6 }}>⚙️</span>Cost Formula Components</h2>
            <span className="tag beam">SHARED</span>
          </div>
          <div className="card-body" style={{ display:'flex', flexDirection:'column', gap:12 }}>
            <CostRow label="Tooling bundle" hint="Applied to every M / MWC plan. Covers plugins, monitoring, backups, etc.">
              <CostInput value={comp.toolingBundle} onChange={v => setComp('toolingBundle', v)} suffix="/mo"/>
            </CostRow>
            <CostRow label="Care labor rate" hint="Per-minute labor rate for included care time on M / MWC plans.">
              <CostInput value={comp.careLaborPerMin} onChange={v => setComp('careLaborPerMin', v)} suffix="/min" step={0.05} width={70}/>
            </CostRow>
            <div style={{ height:1, background:'var(--border)' }}/>
            <CostRow label="Civic cost ratio" hint="% of client charge assumed as internal cost for CIVIC plans (pop-tier municipal sites).">
              <PercentInput value={comp.civicCostRatio} onChange={v => setComp('civicCostRatio', v)}/>
            </CostRow>
            <div style={{ height:1, background:'var(--border)' }}/>
            <CostRow label="Care-only base" hint="Flat tooling cost for CARE-only plans (client hosts elsewhere).">
              <CostInput value={comp.careOnlyBase} onChange={v => setComp('careOnlyBase', v)} suffix="/mo" step={0.5}/>
            </CostRow>
            <CostRow label="Care-only labor rate" hint="Per-minute rate for CARE-only plans.">
              <CostInput value={comp.careOnlyPerMin} onChange={v => setComp('careOnlyPerMin', v)} suffix="/min" step={0.05} width={70}/>
            </CostRow>
          </div>
        </div>

        {/* Right: tooling breakdown */}
        <div className="card">
          <div className="card-head">
            <h2 className="card-title"><span style={{ marginRight:6 }}>🧰</span>Tooling Bundle Breakdown</h2>
            <button className="btn btn-ghost btn-sm" onClick={addBreakdownRow}>
              <Icon name="plus" size={13}/>Add
            </button>
          </div>
          <div className="card-body" style={{ padding:0 }}>
            <table className="table" style={{ fontSize:'.78rem' }}>
              <tbody>
                {comp.toolingBreakdown.map(b => (
                  <tr key={b.id}>
                    <td style={{ width:'60%' }}>
                      <input value={b.label}
                        onChange={e => renameBreakdown(b.id, e.target.value)}
                        style={{ background:'transparent', border:'none', color:'var(--text)', fontSize:'.8rem', width:'100%', outline:'none', padding:'2px 0' }}/>
                    </td>
                    <td style={{ textAlign:'right' }}>
                      <CostInput value={b.cost} onChange={v => setBreakdown(b.id, v)} suffix="/mo" width={70}/>
                    </td>
                    <td style={{ width:30, textAlign:'center' }}>
                      <button className="btn btn-ghost btn-sm" onClick={() => removeBreakdown(b.id)}
                        style={{ padding:'2px 6px', color:'var(--dim)' }} aria-label="Remove">×</button>
                    </td>
                  </tr>
                ))}
              </tbody>
              <tfoot>
                <tr style={{ background:'var(--surface-3)', fontWeight:700 }}>
                  <td>Breakdown total</td>
                  <td className="mono" style={{ textAlign:'right', color:'var(--beam)' }}>${breakdownTotal.toFixed(2)}</td>
                  <td></td>
                </tr>
              </tfoot>
            </table>
            <div style={{ padding:'10px 14px', borderTop:'1px solid var(--border)', display:'flex', justifyContent:'space-between', alignItems:'center', gap:10, flexWrap:'wrap' }}>
              <div style={{ fontSize:'.72rem', color:'var(--dim)' }}>
                {Math.abs(breakdownTotal - comp.toolingBundle) > 0.01 ?
                  <>⚠️ Breakdown total doesn't match tooling bundle (${comp.toolingBundle.toFixed(2)}).</> :
                  <>✓ Breakdown matches tooling bundle.</>}
              </div>
              <button className="btn btn-ghost btn-sm" onClick={applyBreakdownTotal}
                disabled={Math.abs(breakdownTotal - comp.toolingBundle) < 0.01}>
                Apply total → bundle
              </button>
            </div>
          </div>
        </div>
      </div>

      {/* Per-plan overrides */}
      <div className="card">
        <div className="card-head" style={{ gap:12, flexWrap:'wrap' }}>
          <div style={{ display:'flex', alignItems:'center', gap:10, flexWrap:'wrap' }}>
            <h2 className="card-title"><span style={{ marginRight:6 }}>💰</span>Per-Plan Overrides</h2>
            {overrideCount > 0 && <span className="tag warn">{overrideCount} active</span>}
          </div>
          <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
            <div className="tw-seg" style={{ maxWidth:160 }}>
              <button className={showOnly === 'all' ? 'active' : ''} onClick={() => setShowOnly('all')}>All</button>
              <button className={showOnly === 'overridden' ? 'active' : ''} onClick={() => setShowOnly('overridden')}>Overridden</button>
            </div>
            <button className="btn btn-ghost btn-sm" onClick={clearAllOverrides} disabled={overrideCount === 0}>
              Clear overrides
            </button>
            <button className="btn btn-ghost btn-sm" onClick={resetAll}>Reset all</button>
          </div>
        </div>
        <div className="card-body" style={{ padding:'6px 14px 0', borderBottom:'1px solid var(--border)' }}>
          <div className="sub-tabs" style={{ marginBottom:0 }}>
            {['M','MWC','CIVIC','CARE'].map(k => (
              <button key={k} className={'sub-tab' + (overrideTab === k ? ' active' : '')} onClick={() => setOverrideTab(k)}>
                {k === 'M' ? 'M' : k === 'MWC' ? 'MWC' : k === 'CIVIC' ? 'Civic' : 'Care-Only'}
                {' ('}{(CD_PLANS[k === 'CARE' ? 'CARE_ONLY' : k] || []).length}{')'}
              </button>
            ))}
          </div>
        </div>
        <div className="card-body" style={{ padding:0, overflowX:'auto' }}>
          <table className="table" style={{ fontSize:'.78rem', minWidth:780 }}>
            <thead>
              <tr>
                <th>Code</th>
                <th>Label</th>
                <th style={{ textAlign:'right' }}>Default Charge</th>
                <th style={{ textAlign:'right' }}>Override Charge</th>
                <th style={{ textAlign:'right' }}>Default Cost</th>
                <th style={{ textAlign:'right' }}>Override Cost</th>
                <th style={{ textAlign:'right' }}>Effective Margin</th>
                <th style={{ textAlign:'center' }}>Reset</th>
              </tr>
            </thead>
            <tbody>
              {overridePlans
                .filter(p => showOnly === 'all' || ov[p.code])
                .map(p => {
                  const planOv = ov[p.code] || {};
                  // Default cost — calculated WITHOUT overrides
                  const savedState = _hostingCostsState;
                  _hostingCostsState = { ...savedState, overrides: { ...savedState.overrides, [p.code]: undefined } };
                  const defaultCost = window.calcPlanCost(p, overrideTab);
                  _hostingCostsState = savedState;
                  // Effective
                  const effCharge = planOv.charge ?? p.charge;
                  const effCost   = planOv.cost ?? window.calcPlanCost(p, overrideTab);
                  const margin    = effCharge > 0 ? ((effCharge - effCost) / effCharge) * 100 : 0;
                  const mt = margin >= 65 ? 'var(--green)' : margin >= 55 ? 'var(--orange)' : 'var(--rose)';
                  const hasOverride = Object.keys(planOv).length > 0;
                  return (
                    <tr key={p.code} style={{ background: hasOverride ? 'var(--warn-dim)' : 'transparent' }}>
                      <td className="mono" style={{ fontSize:'.7rem', fontWeight:700 }}>{p.code}</td>
                      <td>{p.label}</td>
                      <td className="mono" style={{ textAlign:'right', color:'var(--dim)' }}>${p.charge}</td>
                      <td style={{ textAlign:'right' }}>
                        <CostInput value={planOv.charge ?? ''} onChange={v => setOverride(p.code, 'charge', v)} width={70} step={1}/>
                      </td>
                      <td className="mono" style={{ textAlign:'right', color:'var(--dim)' }}>${defaultCost.toFixed(2)}</td>
                      <td style={{ textAlign:'right' }}>
                        <CostInput value={planOv.cost ?? ''} onChange={v => setOverride(p.code, 'cost', v)} width={80}/>
                      </td>
                      <td className="mono" style={{ textAlign:'right', color: mt, fontWeight:700 }}>{margin.toFixed(1)}%</td>
                      <td style={{ textAlign:'center' }}>
                        {hasOverride ? (
                          <button className="btn btn-ghost btn-sm" onClick={() => setState(s => {
                            const n = { ...s.overrides };
                            delete n[p.code];
                            return { ...s, overrides: n };
                          })} style={{ padding:'2px 8px' }} aria-label={`Reset ${p.code}`}>↺</button>
                        ) : <span style={{ color:'var(--dim)' }}>—</span>}
                      </td>
                    </tr>
                  );
                })}
            </tbody>
          </table>
          {overridePlans.filter(p => showOnly === 'all' || ov[p.code]).length === 0 && (
            <div style={{ padding:'40px 14px', textAlign:'center', color:'var(--dim)', fontSize:'.82rem' }}>
              No overrides on {overrideTab} plans yet. Switch to "All" to set one.
            </div>
          )}
        </div>
        <div className="card-body" style={{ borderTop:'1px solid var(--border)', background:'var(--surface-3)' }}>
          <div style={{ display:'flex', gap:14, flexWrap:'wrap', fontSize:'.72rem', color:'var(--dim)' }}>
            <div><span style={{ display:'inline-block', width:10, height:10, background:'var(--warn-dim)', borderRadius:2, marginRight:4, verticalAlign:'middle' }}/> Overridden row — manual charge or cost set</div>
            <div>Leave override blank to use the default.</div>
          </div>
        </div>
      </div>

      {/* Import / export */}
      <div className="card">
        <div className="card-head">
          <h2 className="card-title"><span style={{ marginRight:6 }}>🔄</span>Import / Export</h2>
        </div>
        <div className="card-body" style={{ display:'flex', gap:10, flexWrap:'wrap', alignItems:'center' }}>
          <button className="btn btn-ghost btn-sm" onClick={() => {
            const json = JSON.stringify(_hostingCostsState, null, 2);
            const blob = new Blob([json], { type:'application/json' });
            const url  = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url; a.download = 'hosting-costs.json'; a.click();
            URL.revokeObjectURL(url);
            window.wpsbToast?.('Exported hosting costs JSON', 'ok');
          }}>⬇ Export costs JSON</button>
          <button className="btn btn-ghost btn-sm" onClick={() => {
            const input = document.createElement('input');
            input.type = 'file'; input.accept = 'application/json';
            input.onchange = async e => {
              const file = e.target.files[0];
              if (!file) return;
              try {
                const text = await file.text();
                const next = JSON.parse(text);
                setState({
                  components: { ...DEFAULT_COST_COMPONENTS, ...(next.components || {}) },
                  overrides:  next.overrides || {},
                });
                window.wpsbToast?.('Imported hosting costs', 'ok');
              } catch (err) {
                window.wpsbToast?.('Import failed — invalid JSON', 'warn');
              }
            };
            input.click();
          }}>⬆ Import costs JSON</button>
          <div style={{ marginLeft:'auto', fontSize:'.72rem', color:'var(--dim)' }}>
            Stored locally · {overrideCount} override{overrideCount === 1 ? '' : 's'} · {comp.toolingBreakdown.length} tooling line{comp.toolingBreakdown.length === 1 ? '' : 's'}
          </div>
        </div>
      </div>
    </div>
  );
}

function CostRow({ label, hint, children }) {
  return (
    <div style={{ display:'flex', alignItems:'center', gap:10, flexWrap:'wrap' }}>
      <div style={{ flex:1, minWidth:180 }}>
        <div style={{ fontSize:'.82rem', fontWeight:600 }}>{label}</div>
        {hint && <div style={{ fontSize:'.7rem', color:'var(--dim)', marginTop:2, lineHeight:1.35 }}>{hint}</div>}
      </div>
      <div>{children}</div>
    </div>
  );
}

window.HostingCostEditor = HostingCostEditor;
