// ledger-modals.jsx — Category + Recurring modals + Settings popover

const { useState: useStateM, useEffect: useEffectM, useRef: useRefM } = React;

// ─────────────── CATEGORY MODAL ───────────────
const CATEGORY_ICONS = [
  '🛒','🍜','☕','🍔','🍕','🍣','🥗','🍷','🍺',
  '🚌','🚕','🚆','✈','⛽','🚗','🛴',
  '🏠','⚡','💧','📶','📱','🔥','🧾',
  '🎬','🎮','🎵','📚','🎨','⚽','🎟','🎭','🎢',
  '🛍','👕','👟','💎','💄','🧴',
  '⚕','💊','💉','🦷','🏥','🧘',
  '🎁','🎂','💐','💌',
  '💷','💼','💰','📈','📊','🧮',
  '🐕','🐈','🌱','🏖','✏','🔧',
];
const CATEGORY_COLORS = [
  'oklch(0.62 0.13 38)',  // terracotta
  'oklch(0.55 0.10 50)',  // amber
  'oklch(0.65 0.13 70)',  // gold
  'oklch(0.55 0.10 150)', // forest
  'oklch(0.60 0.12 130)', // grass
  'oklch(0.58 0.10 165)', // teal
  'oklch(0.55 0.09 220)', // sky
  'oklch(0.55 0.07 240)', // slate
  'oklch(0.55 0.08 280)', // indigo
  'oklch(0.50 0.12 330)', // plum
  'oklch(0.58 0.11 350)', // rose
  'oklch(0.58 0.11 5)',   // coral
  'oklch(0.60 0.01 60)',  // stone
];

function CategoryModal({ category, categories, onClose, onSave, onDelete }) {
  const isNew = !category?.id || !categories.find(c => c.id === category.id);
  const [draft, setDraft] = useStateM(category);
  if (!category) return null;
  const upd = (p) => setDraft(d => ({ ...d, ...p }));

  const inUseCount = isNew ? 0 : (window.__txsCountByCat?.[draft.id] || 0);

  const save = () => {
    if (!draft.name?.trim()) return;
    const id = draft.id || draft.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').slice(0, 24) + '-' + Date.now().toString(36).slice(-3);
    onSave({ ...draft, id, name: draft.name.trim() });
  };

  return (
    <>
      <div onClick={onClose} style={modalOverlay} />
      <div style={modalSheet(480)}>
        <div style={modalHead}>
          <span className="cglyph cglyph-lg" style={{ background: draft.color, color: 'white', fontSize: 20 }}>{draft.icon}</span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div className="micro">{isNew ? 'New category' : 'Edit category'}</div>
            <div style={{ fontSize: 16, fontWeight: 500 }}>{draft.name || 'Untitled'}</div>
          </div>
          <button className="btn ghost icon" onClick={onClose}><Icon name="close" size={16} /></button>
        </div>

        <div style={{ padding: '18px 22px', display: 'flex', flexDirection: 'column', gap: 16, overflow: 'auto' }}>
          <div>
            <div className="micro" style={{ marginBottom: 6 }}>Name</div>
            <div className="field field-lg">
              <input value={draft.name} onChange={e => upd({ name: e.target.value })}
                placeholder="e.g. Subscriptions" autoFocus />
            </div>
          </div>

          <div>
            <div className="micro" style={{ marginBottom: 6 }}>Type</div>
            <div style={{ display: 'flex', background: 'var(--surface-2)', borderRadius: 8, padding: 3, gap: 2 }}>
              {[['out','Expense'],['in','Income']].map(([v,l]) => (
                <button key={v} onClick={() => upd({ kind: v })} style={{
                  flex: 1, padding: '6px', borderRadius: 6,
                  background: draft.kind === v ? 'var(--surface)' : 'transparent',
                  boxShadow: draft.kind === v ? 'var(--shadow-sm)' : 'none',
                  fontSize: 13, fontWeight: 500,
                  color: draft.kind === v ? 'var(--ink)' : 'var(--ink-2)',
                }}>{l}</button>
              ))}
            </div>
          </div>

          <div>
            <div className="micro" style={{ marginBottom: 8 }}>Icon</div>
            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(34px, 1fr))', gap: 4,
              maxHeight: 140, overflow: 'auto',
              background: 'var(--surface-2)', borderRadius: 'var(--r-md)', padding: 6,
            }}>
              {CATEGORY_ICONS.map(i => (
                <button key={i} onClick={() => upd({ icon: i })} style={{
                  width: 34, height: 34, borderRadius: 6,
                  background: draft.icon === i ? draft.color : 'transparent',
                  color: 'white', fontSize: 16, display: 'grid', placeItems: 'center',
                  transition: 'background .1s, transform .06s',
                }}>{i}</button>
              ))}
            </div>
          </div>

          <div>
            <div className="micro" style={{ marginBottom: 8 }}>Color</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
              {CATEGORY_COLORS.map(c => (
                <button key={c} onClick={() => upd({ color: c })} style={{
                  width: 28, height: 28, borderRadius: '50%',
                  background: c,
                  boxShadow: draft.color === c ? `0 0 0 2px var(--bg), 0 0 0 4px ${c}` : 'none',
                  transition: 'box-shadow .12s',
                }} />
              ))}
            </div>
          </div>

          {!isNew && inUseCount > 0 && (
            <div style={{ padding: '8px 12px', background: 'var(--warn-soft)', borderRadius: 'var(--r-sm)', fontSize: 12, color: 'var(--ink-2)' }}>
              ⚠ {inUseCount} transaction{inUseCount > 1 ? 's' : ''} use this category. Deleting will move them to <b>Other</b>.
            </div>
          )}
        </div>

        <div style={modalFoot}>
          {!isNew && (
            <button className="btn ghost" onClick={() => onDelete(draft.id)} style={{ color: 'var(--neg)' }}>
              <Icon name="trash" size={14} /> Delete
            </button>
          )}
          <div style={{ flex: 1 }} />
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn accent" disabled={!draft.name?.trim()} onClick={save}>
            {isNew ? 'Add category' : 'Save'}
          </button>
        </div>
      </div>
    </>
  );
}

// ─────────────── RECURRING MODAL ───────────────
function RecurringModal({ item, onClose, onSave, onDelete }) {
  const isNew = !item?.id;
  const [draft, setDraft] = useStateM(item || { id: null, desc: '', category: 'rent', amount: 0, cadence: 'monthly', nextDate: '2026-06-01' });
  if (!item) return null;
  const upd = (p) => setDraft(d => ({ ...d, ...p }));
  const cat = window.CAT_MAP[draft.category];
  const isIn = cat?.kind === 'in';

  const save = () => {
    if (!draft.desc?.trim() || !draft.amount) return;
    const id = draft.id || 'r' + Date.now().toString(36);
    onSave({ ...draft, id });
  };

  return (
    <>
      <div onClick={onClose} style={modalOverlay} />
      <div style={modalSheet(460)}>
        <div style={modalHead}>
          <span className="cglyph cglyph-lg" style={{ background: cat?.color, color: 'white' }}>{cat?.icon || '🔁'}</span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div className="micro">{isNew ? 'New recurring' : 'Edit recurring'}</div>
            <div style={{ fontSize: 16, fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{draft.desc || 'Untitled'}</div>
          </div>
          <button className="btn ghost icon" onClick={onClose}><Icon name="close" size={16} /></button>
        </div>

        <div style={{ padding: '18px 22px', display: 'flex', flexDirection: 'column', gap: 14, overflow: 'auto' }}>
          <div>
            <div className="micro" style={{ marginBottom: 6 }}>Description</div>
            <div className="field field-lg">
              <input value={draft.desc} onChange={e => upd({ desc: e.target.value })}
                     placeholder="e.g. Spotify, Rent…" autoFocus />
            </div>
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <div>
              <div className="micro" style={{ marginBottom: 6 }}>Amount</div>
              <div className="field field-lg">
                <span style={{ color: 'var(--ink-3)', marginRight: 4 }}>£</span>
                <input type="number" step="0.01" value={draft.amount}
                       onChange={e => upd({ amount: parseFloat(e.target.value) || 0 })}
                       className="tnum" />
              </div>
            </div>
            <div>
              <div className="micro" style={{ marginBottom: 6 }}>Next date</div>
              <div className="field field-lg">
                <input type="date" value={draft.nextDate}
                       onChange={e => upd({ nextDate: e.target.value })} />
              </div>
            </div>
          </div>

          <div>
            <div className="micro" style={{ marginBottom: 6 }}>Category</div>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
              {window.CATEGORIES.map(c => (
                <button key={c.id} onClick={() => upd({ category: c.id })} style={{
                  display: 'inline-flex', alignItems: 'center', gap: 6,
                  padding: '5px 10px', borderRadius: 999,
                  border: draft.category === c.id ? `1px solid ${c.color}` : '1px solid var(--line-2)',
                  background: 'var(--surface)', fontSize: 12.5,
                  boxShadow: draft.category === c.id ? `inset 0 0 0 1px ${c.color}` : 'none',
                }}>
                  <span style={{ fontSize: 14 }}>{c.icon}</span>{c.name}
                </button>
              ))}
            </div>
          </div>

          <div>
            <div className="micro" style={{ marginBottom: 6 }}>Repeats</div>
            <div style={{ display: 'flex', gap: 4 }}>
              {[['weekly','Weekly'],['fortnightly','Every 2 weeks'],['monthly','Monthly'],['yearly','Yearly']].map(([v,l]) => (
                <button key={v} onClick={() => upd({ cadence: v })}
                  className={`chip ${draft.cadence === v ? 'on' : ''}`}>{l}</button>
              ))}
            </div>
          </div>

          <div style={{
            padding: '10px 12px', background: 'var(--surface-2)',
            borderRadius: 'var(--r-sm)', fontSize: 12, color: 'var(--ink-2)',
            display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          }}>
            <span>Preview</span>
            <span className="tnum" style={{ color: isIn ? 'var(--pos)' : 'var(--ink)', fontWeight: 500 }}>
              {isIn ? '+' : '−'}{fmt(draft.amount || 0)} · {draft.cadence}
            </span>
          </div>
        </div>

        <div style={modalFoot}>
          {!isNew && (
            <button className="btn ghost" onClick={() => onDelete(draft.id)} style={{ color: 'var(--neg)' }}>
              <Icon name="trash" size={14} /> Delete
            </button>
          )}
          <div style={{ flex: 1 }} />
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn accent" disabled={!draft.desc?.trim() || !draft.amount} onClick={save}>
            {isNew ? 'Add' : 'Save'}
          </button>
        </div>
      </div>
    </>
  );
}

// ─────────────── SETTINGS MENU (popover from sidebar) ───────────────
function SettingsMenu({ anchorRef, onClose, onSignOut, onClearData, onResetDemo, onExport, onAccount, user }) {
  const ref = useRefM();
  useEffectM(() => {
    const onDown = (e) => {
      if (ref.current && !ref.current.contains(e.target) && anchorRef?.current && !anchorRef.current.contains(e.target)) {
        onClose();
      }
    };
    document.addEventListener('mousedown', onDown);
    return () => document.removeEventListener('mousedown', onDown);
  }, []);

  return (
    <div ref={ref} style={{
      position: 'absolute', bottom: 'calc(100% + 6px)', right: 10,
      width: 240, background: 'var(--surface)',
      border: '1px solid var(--line)', borderRadius: 'var(--r-md)',
      boxShadow: 'var(--shadow-lg)', zIndex: 30,
      padding: 6, animation: 'scaleIn .14s',
    }}>
      <div style={{ padding: '8px 10px 6px', borderBottom: '1px solid var(--line)' }}>
        <div style={{ fontSize: 13, fontWeight: 500 }}>@{user?.username}</div>
        <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>Saved on this device</div>
      </div>
      <MenuRow icon="settings" label="Change username / password" onClick={onAccount} />
      <MenuRow icon="export" label="Export all as CSV" onClick={onExport} />
      <MenuRow icon="repeat" label="Reset to demo data" onClick={onResetDemo} />
      <MenuRow icon="trash" label="Clear all data…" onClick={onClearData} danger />
      <div style={{ height: 1, background: 'var(--line)', margin: '4px 0' }} />
      <MenuRow icon="close" label="Sign out" onClick={onSignOut} />
    </div>
  );
}

function MenuRow({ icon, label, onClick, danger }) {
  return (
    <button onClick={onClick} style={{
      display: 'flex', alignItems: 'center', gap: 10,
      width: '100%', padding: '7px 10px', borderRadius: 'var(--r-sm)',
      fontSize: 13, color: danger ? 'var(--neg)' : 'var(--ink-2)',
      transition: 'background .08s',
    }}
    onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
    onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
    >
      <Icon name={icon} size={14} />
      <span>{label}</span>
    </button>
  );
}

// ─────────────── CONFIRM ───────────────
function ConfirmDialog({ title, body, confirmLabel = 'Confirm', danger = false, onConfirm, onClose }) {
  return (
    <>
      <div onClick={onClose} style={modalOverlay} />
      <div style={modalSheet(360)}>
        <div style={{ padding: '20px 22px 12px' }}>
          <div style={{ fontSize: 17, fontWeight: 500, marginBottom: 6 }}>{title}</div>
          <div style={{ fontSize: 13.5, color: 'var(--ink-2)', lineHeight: 1.45 }}>{body}</div>
        </div>
        <div style={{ padding: '12px 22px', display: 'flex', gap: 8, justifyContent: 'flex-end', borderTop: '1px solid var(--line)', background: 'var(--surface)' }}>
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className={`btn ${danger ? '' : 'accent'}`} onClick={onConfirm}
                  style={danger ? { background: 'var(--neg)', color: 'white', borderColor: 'var(--neg)' } : {}}>
            {confirmLabel}
          </button>
        </div>
      </div>
    </>
  );
}

// ─── shared modal styles ───
const modalOverlay = {
  position: 'fixed', inset: 0, background: 'rgba(40,30,20,.35)',
  backdropFilter: 'blur(2px)', zIndex: 50, animation: 'fadeIn .15s',
};
const modalSheet = (w) => ({
  position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
  width: `min(${w}px, calc(100vw - 32px))`,
  maxHeight: '90vh',
  background: 'var(--bg)', border: '1px solid var(--line)',
  borderRadius: 'var(--r-xl)', boxShadow: 'var(--shadow-lg)', zIndex: 51,
  animation: 'scaleIn .16s', display: 'flex', flexDirection: 'column',
});
const modalHead = {
  padding: '18px 22px 14px', borderBottom: '1px solid var(--line)',
  display: 'flex', alignItems: 'center', gap: 12,
};
const modalFoot = {
  padding: '12px 22px', borderTop: '1px solid var(--line)',
  display: 'flex', gap: 8, background: 'var(--surface)',
};

// ─────────────── ACCOUNT MODAL ───────────────
function AccountModal({ user, onClose, onUsernameChange }) {
  const [tab, setTab] = useStateM('username');
  const [busy, setBusy] = useStateM(false);
  const [msg, setMsg] = useStateM(null); // {type:'ok'|'err', text}

  // username form
  const [newUsername, setNewUsername] = useStateM(user?.username || '');
  const [curPw1, setCurPw1] = useStateM('');

  // password form
  const [curPw2, setCurPw2] = useStateM('');
  const [newPw, setNewPw] = useStateM('');
  const [newPw2, setNewPw2] = useStateM('');

  const ok = (text) => setMsg({ type: 'ok', text });
  const err = (text) => setMsg({ type: 'err', text });

  const saveUsername = async (e) => {
    e?.preventDefault();
    setMsg(null);
    if (!newUsername.trim()) return err('Username cannot be empty');
    if (newUsername.trim() === user.username) return err('Same as current username');
    if (!curPw1) return err('Enter your current password');
    setBusy(true);
    try {
      await AUTH.changeUsername(curPw1, newUsername);
      onUsernameChange({ username: newUsername.trim() });
      ok('Username updated');
      setCurPw1('');
    } catch (e) {
      err(e.message);
    } finally { setBusy(false); }
  };

  const savePassword = async (e) => {
    e?.preventDefault();
    setMsg(null);
    if (!curPw2 || !newPw || !newPw2) return err('Fill in all fields');
    if (newPw !== newPw2) return err("New passwords don't match");
    if (newPw.length < 4) return err('Password must be 4+ chars');
    setBusy(true);
    try {
      await AUTH.changePassword(curPw2, newPw);
      ok('Password updated');
      setCurPw2(''); setNewPw(''); setNewPw2('');
    } catch (e) {
      err(e.message);
    } finally { setBusy(false); }
  };

  return (
    <>
      <div onClick={onClose} style={modalOverlay} />
      <div style={modalSheet(440)}>
        <div style={modalHead}>
          <span className="cglyph cglyph-lg" style={{ background: 'var(--ink)', color: 'var(--bg)', fontSize: 17 }}>
            {(user?.username || '?')[0].toUpperCase()}
          </span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div className="micro">Account</div>
            <div style={{ fontSize: 16, fontWeight: 500 }}>@{user?.username}</div>
          </div>
          <button className="btn ghost icon" onClick={onClose}><Icon name="close" size={16} /></button>
        </div>

        <div style={{ padding: '4px 22px 0', display: 'flex', gap: 4, borderBottom: '1px solid var(--line)' }}>
          {[['username', 'Change username'], ['password', 'Change password']].map(([v, l]) => (
            <button key={v} onClick={() => { setTab(v); setMsg(null); }} style={{
              padding: '10px 4px', fontSize: 13, fontWeight: 500,
              color: tab === v ? 'var(--ink)' : 'var(--ink-3)',
              borderBottom: tab === v ? '2px solid var(--accent)' : '2px solid transparent',
              marginRight: 16,
            }}>{l}</button>
          ))}
        </div>

        {tab === 'username' ? (
          <form onSubmit={saveUsername} style={{ padding: '18px 22px', display: 'flex', flexDirection: 'column', gap: 14, overflow: 'auto' }}>
            <div>
              <div className="micro" style={{ marginBottom: 6 }}>New username</div>
              <div className="field field-lg">
                <input value={newUsername} onChange={e => setNewUsername(e.target.value)}
                       placeholder="e.g. danny2" autoFocus disabled={busy} />
              </div>
            </div>
            <div>
              <div className="micro" style={{ marginBottom: 6 }}>Current password</div>
              <div className="field field-lg">
                <input type="password" value={curPw1} onChange={e => setCurPw1(e.target.value)} disabled={busy} />
              </div>
            </div>
            {msg && <AccountMsg msg={msg} />}
            <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
              <button type="button" className="btn" onClick={onClose}>Cancel</button>
              <button type="submit" className="btn accent" disabled={busy}>Update username</button>
            </div>
          </form>
        ) : (
          <form onSubmit={savePassword} style={{ padding: '18px 22px', display: 'flex', flexDirection: 'column', gap: 14, overflow: 'auto' }}>
            <div>
              <div className="micro" style={{ marginBottom: 6 }}>Current password</div>
              <div className="field field-lg">
                <input type="password" value={curPw2} onChange={e => setCurPw2(e.target.value)}
                       autoComplete="current-password" autoFocus disabled={busy} />
              </div>
            </div>
            <div>
              <div className="micro" style={{ marginBottom: 6 }}>New password</div>
              <div className="field field-lg">
                <input type="password" value={newPw} onChange={e => setNewPw(e.target.value)}
                       autoComplete="new-password" placeholder="at least 4 characters" disabled={busy} />
              </div>
            </div>
            <div>
              <div className="micro" style={{ marginBottom: 6 }}>Confirm new password</div>
              <div className="field field-lg">
                <input type="password" value={newPw2} onChange={e => setNewPw2(e.target.value)}
                       autoComplete="new-password" disabled={busy} />
              </div>
            </div>
            {msg && <AccountMsg msg={msg} />}
            <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end', marginTop: 4 }}>
              <button type="button" className="btn" onClick={onClose}>Cancel</button>
              <button type="submit" className="btn accent" disabled={busy}>Update password</button>
            </div>
          </form>
        )}
      </div>
    </>
  );
}

function AccountMsg({ msg }) {
  const isOk = msg.type === 'ok';
  return (
    <div style={{
      padding: '8px 12px', borderRadius: 'var(--r-sm)', fontSize: 12.5,
      background: isOk ? 'var(--pos-soft)' : 'oklch(0.95 0.04 28)',
      color: isOk ? 'var(--pos)' : 'var(--neg)',
      display: 'flex', alignItems: 'center', gap: 6,
    }}>
      <Icon name={isOk ? 'check' : 'close'} size={13} />
      {msg.text}
    </div>
  );
}

Object.assign(window, { CategoryModal, RecurringModal, SettingsMenu, ConfirmDialog, AccountModal });
