// Profile manager — preset picker (filtered, collapsible) + custom editor + JSON save/load
const { useState, useRef, useMemo } = React;

function profilesEqual(a, b) {
  const keys = ['name','cartridge','type','weight_g','diameter_mm','muzzleVel_mps','bc_G1','bc_G7','dragModel','stabilityFactor','sightHeight_m','zeroDist_m','railCant_mrad','scopeMaxElevation_mrad'];
  for (const k of keys) {
    const av = a[k] == null ? '' : a[k];
    const bv = b[k] == null ? '' : b[k];
    if (typeof av === 'number' && typeof bv === 'number') {
      if (Math.abs(av - bv) > 1e-9) return false;
    } else if (av !== bv) return false;
  }
  return true;
}

function nextCustomName(base, customs) {
  let i = 1;
  while (customs.some(c => c.name === `${base} (${i})`)) i++;
  return `${base} (${i})`;
}

const ProfilePanel = ({ profile, setProfile, presets, customs, setCustoms, units }) => {
  const u = units || 'metric';
  const imp = u === 'imperial';
  const wt = (p) => imp ? `${(p.weight_g * 15.4324).toFixed(0)}gr` : `${p.weight_g.toFixed(2)}g`;
  const mv = (p) => imp ? `${(p.muzzleVel_mps * 3.28084).toFixed(0)} fps` : `${p.muzzleVel_mps} m/s`;
  const me = (p) => {
    const j = 0.5 * (p.weight_g / 1000) * p.muzzleVel_mps * p.muzzleVel_mps;
    return imp ? `${(j * 0.737562).toFixed(0)} ft·lb` : `${j.toFixed(0)} J`;
  };
  const dia = (mm) => imp ? `${(mm / 25.4).toFixed(3)} in` : `${mm} mm`;
  // SI-only sanitization for export — strips any imperial-named legacy fields
  function sanitize(p) {
    const { weight_gr, ...rest } = p;
    return rest;
  }
  const fileInput = useRef();
  const [editing, setEditing] = useState(false);
  const [collapsed, setCollapsed] = useState({});
  const [filterCaliber, setFilterCaliber] = useState('all');
  const [filterMfr, setFilterMfr] = useState('Sako');

  const isBuiltIn = !profile.custom;

  function persistCustoms(next) {
    setCustoms(next);
    localStorage.setItem('cb_customs', JSON.stringify(next));
  }

  function selectPreset(id) {
    const p = presets.find(x => x.id === id) || customs.find(x => x.id === id);
    if (p) setProfile({ ...p });
  }

  // When editing: built-ins fork to a new custom on first change. Customs edit in-place.
  function onEdit(patch) {
    const merged = { ...profile, ...patch };
    if (isBuiltIn) {
      // Only fork if something actually changed
      const original = presets.find(p => p.id === profile.id);
      if (original && profilesEqual(merged, original)) {
        setProfile(merged);
        return;
      }
      const baseName = (profile.name || 'Custom').replace(/\s*\(\d+\)\s*$/, '');
      const newName = nextCustomName(baseName, customs);
      const forked = { ...merged, id: 'custom-' + Date.now(), name: newName, custom: true, basedOn: profile.id };
      const next = [...customs, forked];
      persistCustoms(next);
      setProfile(forked);
    } else {
      // Custom — edit in place + persist
      const next = customs.map(c => c.id === profile.id ? merged : c);
      persistCustoms(next);
      setProfile(merged);
    }
  }

  function exportJson() {
    const blob = new Blob([JSON.stringify(sanitize(profile), null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = (profile.name || 'profile').replace(/\s+/g, '_') + '.cbprofile.json';
    a.click();
    URL.revokeObjectURL(url);
  }

  function importJson(e) {
    const f = e.target.files[0]; if (!f) return;
    const reader = new FileReader();
    reader.onload = (ev) => {
      try {
        const obj = JSON.parse(ev.target.result);
        // Backfill weight_g if a legacy file shipped only weight_gr
        if (obj.weight_g == null && obj.weight_gr != null) obj.weight_g = +(obj.weight_gr / 15.4324).toFixed(2);
        const clean = sanitize(obj);
        const newName = nextCustomName((clean.name || 'Imported').replace(/\s*\(\d+\)\s*$/, ''), customs);
        const newP = { ...clean, id: 'custom-' + Date.now(), name: newName, custom: true };
        persistCustoms([...customs, newP]);
        setProfile(newP);
      } catch (err) { alert('Invalid profile JSON'); }
    };
    reader.readAsText(f);
    e.target.value = '';
  }

  function duplicateCurrent() {
    const baseName = (profile.name || 'Profile').replace(/\s*\(\d+\)\s*$/, '');
    const newP = { ...profile, id: 'custom-' + Date.now(), name: nextCustomName(baseName, customs), custom: true };
    persistCustoms([...customs, newP]);
    setProfile(newP);
  }

  function deleteCustom(id) {
    if (!confirm('Delete this saved profile?')) return;
    persistCustoms(customs.filter(c => c.id !== id));
  }

  function renameCustom(id) {
    const p = customs.find(c => c.id === id); if (!p) return;
    const v = prompt('Rename profile', p.name); if (!v) return;
    const next = customs.map(c => c.id === id ? { ...c, name: v } : c);
    persistCustoms(next);
    if (profile.id === id) setProfile({ ...profile, name: v });
  }

  const manufacturers = useMemo(() => {
    const set = new Set(presets.map(p => p.manufacturer || 'Other'));
    return ['all', ...Array.from(set).sort()];
  }, [presets]);

  const calibers = useMemo(() => {
    const set = new Set(presets.map(p => p.cartridge));
    return ['all', ...Array.from(set).sort()];
  }, [presets]);

  const filtered = useMemo(() => presets.filter(p =>
    (filterMfr === 'all' || (p.manufacturer || 'Other') === filterMfr) &&
    (filterCaliber === 'all' || p.cartridge === filterCaliber)
  ), [presets, filterMfr, filterCaliber]);

  const byCart = {};
  filtered.forEach(p => { (byCart[p.cartridge] = byCart[p.cartridge] || []).push(p); });

  return (
    <div className="panel">
      <div className="panel-h">
        <span>BULLET PROFILE {isBuiltIn ? <span className="builtin-tag">BUILT-IN</span> : <span className="custom-tag">CUSTOM</span>}</span>
        <button className="ghost-btn" onClick={() => setEditing(!editing)}>{editing ? 'DONE' : 'EDIT'}</button>
      </div>
      <div className="profile-summary">
        <div className="profile-name">{profile.name}</div>
        <div className="profile-cart">{profile.cartridge} · {wt(profile)} · {dia(profile.diameter_mm)}</div>
        <div className="profile-type">{profile.type}</div>
        <div className="kv-row">
          <div><label>Muzzle V</label><span>{mv(profile)}</span></div>
          <div><label>Muzzle E</label><span>{me(profile)}</span></div>
          <div><label>BC G1</label><span>{profile.bc_G1}</span></div>
          <div><label>BC G7</label><span>{profile.bc_G7}</span></div>
          <div><label>Drag</label><span>{profile.dragModel}</span></div>
        </div>
      </div>

      <div className="row tight">
        <button className="ghost-btn" onClick={duplicateCurrent}>+ DUPLICATE</button>
        <button className="ghost-btn" onClick={exportJson}>↓ SAVE TO FILE</button>
        <button className="ghost-btn" onClick={() => fileInput.current.click()}>↑ LOAD FROM FILE</button>
        <input ref={fileInput} type="file" accept=".json,.cbprofile.json,application/json" onChange={importJson} style={{ display: 'none' }} />
      </div>
      {isBuiltIn && editing && (
        <div className="model-desc">Built-in profiles are read-only. Editing any value forks to a new custom profile automatically.</div>
      )}

      {editing && (
        <div className="profile-editor">
          <FieldRow label="Name" value={profile.name} onChange={v => onEdit({ name: v })} />
          <FieldRow label="Cartridge" value={profile.cartridge} onChange={v => onEdit({ cartridge: v })} />
          <FieldRow label="Type" value={profile.type} onChange={v => onEdit({ type: v })} />
          <FieldGrid>
            {imp ? (
              <NumberField label="Weight (gr)" value={+(profile.weight_g * 15.4324).toFixed(0)} step={1}
                onChange={v => onEdit({ weight_g: v / 15.4324 })} />
            ) : (
              <NumberField label="Weight (g)" value={+profile.weight_g.toFixed(2)} step={0.01}
                onChange={v => onEdit({ weight_g: v })} />
            )}
            {imp ? (
              <NumberField label="Diameter (in)" value={+(profile.diameter_mm / 25.4).toFixed(3)} step={0.001}
                onChange={v => onEdit({ diameter_mm: v * 25.4 })} />
            ) : (
              <NumberField label="Diameter (mm)" value={profile.diameter_mm} step={0.01}
                onChange={v => onEdit({ diameter_mm: v })} />
            )}
            {imp ? (
              <NumberField label="Muzzle V (fps)" value={+(profile.muzzleVel_mps * 3.28084).toFixed(0)} step={10}
                onChange={v => onEdit({ muzzleVel_mps: v / 3.28084 })} />
            ) : (
              <NumberField label="Muzzle V (m/s)" value={profile.muzzleVel_mps} step={5}
                onChange={v => onEdit({ muzzleVel_mps: v })} />
            )}
            <NumberField label="BC G1" value={profile.bc_G1} step={0.005} onChange={v => onEdit({ bc_G1: v })} />
            <NumberField label="BC G7" value={profile.bc_G7} step={0.005} onChange={v => onEdit({ bc_G7: v })} />
          </FieldGrid>
          <div className="seg">
            <label>Drag model</label>
            <div className="seg-options">
              {['G1', 'G7'].map(m => (
                <button key={m} className={profile.dragModel === m ? 'on' : ''} onClick={() => onEdit({ dragModel: m })}>{m}</button>
              ))}
            </div>
          </div>
          <FieldGrid>
            <NumberField label="Sight ht (m)" value={profile.sightHeight_m} step={0.005} onChange={v => onEdit({ sightHeight_m: v })} />
            <NumberField label="Zero (m)" value={profile.zeroDist_m} step={25} onChange={v => onEdit({ zeroDist_m: v })} />
            <NumberField label="Stab. SG" value={profile.stabilityFactor || 1.5} step={0.1} onChange={v => onEdit({ stabilityFactor: v })} />
          </FieldGrid>
        </div>
      )}

      <div className="panel-h sub">PRELOADED</div>
      <div className="filter-row">
        <label className="filter-field">
          <span>Manufacturer</span>
          <select value={filterMfr} onChange={e => setFilterMfr(e.target.value)}>
            {manufacturers.map(m => <option key={m} value={m}>{m === 'all' ? 'All' : m}</option>)}
          </select>
        </label>
        <label className="filter-field">
          <span>Calibre</span>
          <select value={filterCaliber} onChange={e => setFilterCaliber(e.target.value)}>
            {calibers.map(c => <option key={c} value={c}>{c === 'all' ? 'All' : c}</option>)}
          </select>
        </label>
      </div>

      <div className="preset-list">
        {Object.keys(byCart).length === 0 && <div className="empty">No profiles match filters.</div>}
        {Object.keys(byCart).map(cart => {
          const isCol = collapsed[cart];
          return (
            <div key={cart} className="cart-group">
              <button className="cart-toggle" onClick={() => setCollapsed({ ...collapsed, [cart]: !isCol })}>
                <span className="cart-chev">{isCol ? '▶' : '▼'}</span>
                <span className="cart-name">{cart}</span>
                <span className="cart-count">{byCart[cart].length}</span>
              </button>
              {!isCol && byCart[cart].map(p => (
                <button key={p.id} className={'preset-btn' + (p.id === profile.id ? ' active' : '')} onClick={() => selectPreset(p.id)}>
                  <span className="pname">{p.name}</span>
                  <span className="pmeta">{wt(p)} · {mv(p)}</span>
                  <span className="ptype">{(p.type || '').split('·')[0]}</span>
                </button>
              ))}
            </div>
          );
        })}
      </div>

      {customs.length > 0 && <>
        <div className="panel-h sub">SAVED · CUSTOM</div>
        <div className="preset-list">
          {customs.map(p => (
            <div key={p.id} className="custom-row">
              <button className={'preset-btn' + (p.id === profile.id ? ' active' : '')} onClick={() => selectPreset(p.id)}>
                <span className="pname">{p.name}</span>
                <span className="pmeta">{p.cartridge} · {wt(p)}</span>
              </button>
              <button className="ghost-btn small" title="Rename" onClick={() => renameCustom(p.id)}>✎</button>
              <button className="ghost-btn small" title="Delete" onClick={() => deleteCustom(p.id)}>×</button>
            </div>
          ))}
        </div>
      </>}
    </div>
  );
};

const FieldRow = ({ label, value, onChange }) => (
  <div className="field">
    <label>{label}</label>
    <input value={value || ''} onChange={e => onChange(e.target.value)} />
  </div>
);
const NumberField = ({ label, value, step, onChange }) => (
  <div className="field">
    <label>{label}</label>
    <input type="number" step={step} value={value} onChange={e => onChange(parseFloat(e.target.value))} />
  </div>
);
const FieldGrid = ({ children }) => <div className="field-grid">{children}</div>;

window.ProfilePanel = ProfilePanel;
window.FieldGrid = FieldGrid;
window.NumberField = NumberField;
