// src/features/calendar/ui/availability-picker.jsx
//
// Two components that read & write availability blocks:
//
//   <AvailabilityPicker value onChange [timezone onTimezoneChange] />
//     One row per weekday + enable toggle + start/end dropdowns + multi-block.
//     Stores blocks in the shape:
//       { 0:{ enabled, blocks:[{from,to}] }, ... }  (Mon=0)
//     `from`/`to` are decimal hours (9, 9.5, 17, 24 = end-of-day sentinel).
//
//   <TimezoneBadge value [onChange] />
//     "Times in: <zone>" pill. Read-only by default; pass onChange to
//     turn it into an inline native <select>.
//
// All shape conversions (UI blocks ↔ DB rows ↔ grid cells) live in
// src/features/calendar/utils.js as window.Calendar.shape.*. This file
// only renders / mutates the UI shape — it never touches the DB.

const AVP_DAYS = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'];

// Every half-hour 12:00 AM → 11:30 PM, plus "12:00 AM (next day)" for end.
const AVP_TIMES = (() => {
  const out = [];
  for (let h = 0; h < 24; h++) {
    out.push(h);
    out.push(h + 0.5);
  }
  out.push(24);
  return out;
})();

const avpFmt = (v) => {
  if (v === 24) return '12:00 AM (next day)';
  const h = Math.floor(v);
  const m = (v - h) === 0.5 ? '30' : '00';
  const ampm = h < 12 ? 'AM' : 'PM';
  const h12  = h % 12 === 0 ? 12 : h % 12;
  return `${h12}:${m} ${ampm}`;
};

const avpDefaultDay = () => ({ enabled:false, blocks:[{from:9, to:17}] });

const AvailabilityPicker = ({ value, onChange, compact = false, timezone, onTimezoneChange }) => {
  // Timezone dropdown is opt-in: parents that don't pass `timezone` +
  // `onTimezoneChange` get the picker without it.
  const showTimezone = (typeof timezone !== 'undefined') && (typeof onTimezoneChange === 'function');
  const avail = (typeof value === 'object' && value)
    ? Object.fromEntries([0,1,2,3,4,5,6].map(i => [i, value[i] || avpDefaultDay()]))
    : Object.fromEntries([0,1,2,3,4,5,6].map(i => [i, avpDefaultDay()]));

  const setDay = (i, next) => onChange({ ...avail, [i]: next });

  const toggle = (i) => {
    const d = avail[i] || avpDefaultDay();
    setDay(i, { ...d, enabled: !d.enabled, blocks: d.blocks?.length ? d.blocks : [{from:9, to:17}] });
  };
  const setBlock = (i, bi, key, val) => {
    const d = avail[i] || avpDefaultDay();
    const blocks = (d.blocks || []).map((b, idx) => idx === bi ? { ...b, [key]: Number(val) } : b);
    setDay(i, { ...d, enabled: true, blocks });
  };
  const addBlock = (i) => {
    const d = avail[i] || avpDefaultDay();
    const last = (d.blocks || []).at(-1) || { from:9, to:17 };
    const from = Math.min(last.to, 23);
    const to   = Math.min(from + 2, 24);
    setDay(i, { ...d, enabled: true, blocks: [...(d.blocks || []), { from, to }] });
  };
  const removeBlock = (i, bi) => {
    const d = avail[i] || avpDefaultDay();
    const blocks = (d.blocks || []).filter((_, idx) => idx !== bi);
    setDay(i, { ...d, blocks: blocks.length ? blocks : [{ from:9, to:17 }] });
  };

  const tinySel = {
    padding: compact ? '5px 8px' : '7px 10px', borderRadius:7, border:'1.5px solid oklch(86% 0.02 265)',
    fontSize: compact ? 12 : 13, fontFamily:"'Plus Jakarta Sans', sans-serif",
    color:'oklch(22% 0.06 265)', background:'#fff', cursor:'pointer', outline:'none',
  };

  const tzSelected = timezone || 'America/New_York';
  const tzAll      = showTimezone ? window.Calendar.time.zones() : [];

  return (
    <div style={{ display:'flex', flexDirection:'column', gap: compact ? 6 : 8 }}>
      {AVP_DAYS.map((dayName, i) => {
        const d      = avail[i] || avpDefaultDay();
        const blocks = d.blocks || [{ from:9, to:17 }];
        return (
          <div key={i} style={{
            borderRadius: compact ? 8 : 10,
            border: `1.5px solid ${d.enabled ? 'oklch(22% 0.06 265)' : 'oklch(90% 0.012 265)'}`,
            background: d.enabled ? 'oklch(98.5% 0.005 265)' : '#fff',
            overflow:'hidden', transition:'all 0.12s',
          }}>
            <div style={{ display:'flex', alignItems:'center', gap: compact ? 8 : 12, padding: compact ? '8px 10px' : '10px 14px' }}>
              <button type="button" onClick={() => toggle(i)} style={{
                width:38, height:20, borderRadius:11, border:'none',
                background: d.enabled ? 'oklch(22% 0.06 265)' : 'oklch(86% 0.013 265)',
                cursor:'pointer', position:'relative', flexShrink:0,
              }}>
                <div style={{ width:14, height:14, borderRadius:'50%', background:'#fff', position:'absolute',
                  top:3, left: d.enabled ? 21 : 3, transition:'left 0.15s', boxShadow:'0 1px 3px rgba(0,0,0,0.18)' }} />
              </button>
              <span style={{
                fontSize: compact ? 12 : 13, fontWeight: d.enabled ? 700 : 500,
                color: d.enabled ? 'oklch(20% 0.04 265)' : 'oklch(60% 0.03 265)',
                minWidth: compact ? 78 : 92, flexShrink:0,
              }}>{dayName}</span>
              {!d.enabled && <span style={{ fontSize:11, color:'oklch(70% 0.02 265)', fontStyle:'italic' }}>Off</span>}
            </div>
            {d.enabled && (
              <div style={{ padding: compact ? '0 10px 10px 10px' : '0 14px 12px 14px', display:'flex', flexDirection:'column', gap:6 }}>
                {blocks.map((b, bi) => (
                  <div key={bi} style={{ display:'flex', alignItems:'center', gap:6, flexWrap:'wrap' }}>
                    <select value={b.from} onChange={e => setBlock(i, bi, 'from', e.target.value)} style={tinySel}>
                      {AVP_TIMES.filter(t => t < 24).map(t => (
                        <option key={t} value={t}>{avpFmt(t)}</option>
                      ))}
                    </select>
                    <span style={{ fontSize:12, color:'oklch(56% 0.03 265)' }}>to</span>
                    <select value={b.to} onChange={e => setBlock(i, bi, 'to', e.target.value)} style={tinySel}>
                      {AVP_TIMES.filter(t => t > b.from).map(t => (
                        <option key={t} value={t}>{avpFmt(t)}</option>
                      ))}
                    </select>
                    {blocks.length > 1 && (
                      <button type="button" onClick={() => removeBlock(i, bi)} style={{
                        background:'none', border:'none', cursor:'pointer', fontSize:18,
                        color:'oklch(68% 0.02 265)', padding:'0 4px', lineHeight:1,
                      }}>×</button>
                    )}
                  </div>
                ))}
                <button type="button" onClick={() => addBlock(i)} style={{
                  alignSelf:'flex-start', background:'none', border:'none',
                  fontSize:11, fontWeight:600, color:'oklch(36% 0.08 265)',
                  cursor:'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif", padding:'2px 0',
                }}>+ Add another block</button>
              </div>
            )}
          </div>
        );
      })}
      {showTimezone && (
        <div style={{
          marginTop: compact ? 4 : 6,
          padding: compact ? '10px 12px' : '12px 14px',
          borderRadius: compact ? 8 : 10,
          border: '1.5px solid oklch(90% 0.012 265)',
          background: 'oklch(98.5% 0.005 265)',
          display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap',
        }}>
          <div style={{ display:'flex', flexDirection:'column', flex:'1 1 200px', minWidth:0 }}>
            <span style={{
              fontSize: 10, fontWeight: 700, textTransform: 'uppercase',
              letterSpacing: '0.07em', color: 'oklch(52% 0.04 265)', marginBottom: 4,
            }}>Time zone</span>
            <span style={{ fontSize: 11, color: 'oklch(58% 0.03 265)', lineHeight: 1.4 }}>
              All start/end times above are interpreted in this zone.
            </span>
          </div>
          <select
            value={tzSelected}
            onChange={e => onTimezoneChange(e.target.value)}
            style={{
              ...tinySel,
              minWidth: compact ? 220 : 260,
              padding: compact ? '7px 10px' : '9px 12px',
              fontSize: compact ? 12 : 13,
              flexShrink: 0,
            }}
          >
            <optgroup label="Common">
              {window.Calendar.time.commonZones.map(o => (
                <option key={'c-' + o.value} value={o.value}>{o.label}</option>
              ))}
            </optgroup>
            {tzAll.map(g => (
              <optgroup key={g.region} label={g.region}>
                {g.zones.map(z => (
                  <option key={g.region + '-' + z.value} value={z.value}>{z.label}</option>
                ))}
              </optgroup>
            ))}
          </select>
        </div>
      )}
    </div>
  );
};

// Tiny "Times in: <zone>" pill that goes at the top of any page/modal
// showing times to the user. Read-only by default; pass `onChange` to
// turn the pill into an inline native <select>.
const TimezoneBadge = ({ value, onChange, compact = false }) => {
  const detected = window.Calendar.time.detect();
  const tz = value || detected;
  const common = window.Calendar.time.commonZones.find(o => o.value === tz);
  const label = common
    ? common.label
    : tz.replace(/_/g, ' ');
  const short = tz.includes('/')
    ? tz.slice(tz.lastIndexOf('/') + 1).replace(/_/g, ' ')
    : tz;

  const wrap = {
    display: 'inline-flex', alignItems: 'center', gap: 6,
    background: 'oklch(96.5% 0.008 265)',
    border: '1px solid oklch(90% 0.012 265)',
    borderRadius: 999,
    padding: compact ? '5px 12px' : '7px 14px',
    fontFamily: "'Plus Jakarta Sans', sans-serif",
    fontSize: compact ? 12 : 13,
    color: 'oklch(40% 0.04 265)',
    maxWidth: '100%',
    minWidth: 0,
    boxSizing: 'border-box',
    lineHeight: 1.2,
  };
  const dot = {
    width: 6, height: 6, borderRadius: '50%',
    background: 'oklch(56% 0.13 250)', flexShrink: 0,
  };
  const valueText = {
    fontWeight: 600,
    color: 'oklch(28% 0.05 265)',
    whiteSpace: 'nowrap',
    overflow: 'hidden',
    textOverflow: 'ellipsis',
    minWidth: 0,
  };

  if (typeof onChange !== 'function') {
    return (
      <span style={wrap} title={`All times shown in ${label}`}>
        <span style={dot} />
        <span style={{ fontWeight: 600, flexShrink: 0 }}>Times in:</span>
        <span style={valueText}>{short}</span>
      </span>
    );
  }
  const tzAll = window.Calendar.time.zones();
  // Overlay invisible native <select> so mobile gets the native picker
  // but the visible chrome stays styled. fontSize:16 stops iOS zooming.
  return (
    <label style={{ ...wrap, position: 'relative', cursor: 'pointer' }} title={`All times shown in ${label}`}>
      <span style={dot} />
      <span style={{ fontWeight: 600, flexShrink: 0 }}>Times in:</span>
      <span style={valueText}>{short}</span>
      <span aria-hidden style={{ fontSize: 9, color: 'oklch(50% 0.04 265)', marginLeft: 2, flexShrink: 0 }}>▾</span>
      <select
        value={tz}
        onChange={e => onChange(e.target.value)}
        aria-label="Change displayed timezone"
        style={{
          position: 'absolute', inset: 0,
          width: '100%', height: '100%',
          opacity: 0, cursor: 'pointer',
          fontSize: 16,
          border: 'none', background: 'transparent',
          appearance: 'none', WebkitAppearance: 'none',
        }}
      >
        <optgroup label="Common">
          {window.Calendar.time.commonZones.map(o => (
            <option key={'tb-c-' + o.value} value={o.value}>{o.label}</option>
          ))}
        </optgroup>
        {tzAll.map(g => (
          <optgroup key={'tb-' + g.region} label={g.region}>
            {g.zones.map(z => (
              <option key={'tb-' + g.region + '-' + z.value} value={z.value}>{z.label}</option>
            ))}
          </optgroup>
        ))}
      </select>
    </label>
  );
};

// Public: under the Calendar.ui.* namespace (canonical), plus the old
// bare globals (backward-compat for callers not yet migrated).
window.Calendar.ui = window.Calendar.ui || {};
window.Calendar.ui.AvailabilityPicker = AvailabilityPicker;
window.Calendar.ui.TimezoneBadge      = TimezoneBadge;
window.AvailabilityPicker             = AvailabilityPicker;
window.TimezoneBadge                  = TimezoneBadge;
