import { load, save } from './storage';
import * as FontSize    from './features/font-size';
import * as Contrast    from './features/contrast';
import * as Dyslexia    from './features/dyslexia-font';
import * as Grayscale   from './features/grayscale';
import * as ReadGuide   from './features/reading-guide';
import * as Animations  from './features/animations';
import * as LineHeight  from './features/line-height';
import * as Cursor      from './features/cursor-enlarger';
import * as Links       from './features/highlight-links';
import * as ScreenMask  from './features/screen-mask';

export interface WidgetConfig {
  enabled?: boolean;
  color: string;
  position: string;
  features: string[];
  hide_powered_by?: boolean;
}

type ToggleState = Record<string, boolean>;

const FEATURE_LABELS: Record<string, string> = {
  font:           'Font Size',
  contrast:       'High Contrast',
  dyslexia:       'Dyslexia Font',
  grayscale:      'Grayscale',
  'reading-guide':'Reading Guide',
  animations:     'Pause Animations',
  'line-height':  'Line Height',
  cursor:         'Large Cursor',
  links:          'Highlight Links',
  'screen-mask':  'Screen Mask',
};

const FEATURE_ICONS: Record<string, string> = {
  font:            'Aa',
  contrast:        '◑',
  dyslexia:        '\u{1D4BB}', // 𝒻 script f — indicates special font
  grayscale:       '◌',
  'reading-guide': '☰',
  animations:      '⏸',
  'line-height':   '↕',
  cursor:          '↖',
  links:           '⬡',
  'screen-mask':   '▤',
};

const CSS = `
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
.w{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;font-size:14px;line-height:1.4;color:#1e1e2e}
.fab{width:52px;height:52px;border-radius:50%;border:2px solid rgba(255,255,255,.25);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:24px;color:#fff;box-shadow:0 2px 14px rgba(0,0,0,.28);transition:transform .15s}
.fab:hover{transform:scale(1.06)}
.fab:focus-visible{outline:3px solid #fff;outline-offset:4px;box-shadow:0 0 0 7px rgba(255,255,255,.28)}
.panel{position:absolute;width:292px;background:#fff;border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,.18);overflow:hidden;transition:opacity .15s,transform .15s}
.panel.hidden{display:none}
.ph{display:flex;align-items:center;justify-content:space-between;padding:12px 14px 11px;border-bottom:1px solid #e5e7eb}
.pt{font-size:14px;font-weight:700}
.xb{background:none;border:none;cursor:pointer;font-size:17px;color:#6b7280;padding:4px 6px;border-radius:6px;line-height:1}
.xb:hover{background:#f3f4f6}
.xb:focus-visible{outline:2px solid var(--c);outline-offset:2px;background:#f3f4f6}
.fs{padding:6px 8px 8px;max-height:380px;overflow-y:auto}
.fr{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 8px;border-radius:8px;transition:background .12s,box-shadow .12s}
.fr:hover{background:#f0f4ff;box-shadow:inset 0 0 0 2px var(--c)}
.fr.fr-toggle{cursor:pointer}
.fr.fr-toggle:focus-visible{outline:2px solid var(--c);outline-offset:2px;background:#f0f4ff}
.fi{font-size:20px;width:28px;flex-shrink:0;display:flex;align-items:center;justify-content:center;line-height:1;opacity:.75}
.fl{font-size:13px;font-weight:500;flex:1}
.tb{width:44px;height:24px;border-radius:12px;border:none;cursor:pointer;position:relative;background:#d1d5db;flex-shrink:0;transition:background .18s}
.tb[aria-pressed=true]{background:var(--c)}
.tb::after{content:'';position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:#fff;transition:transform .18s;box-shadow:0 1px 3px rgba(0,0,0,.2)}
.tb[aria-pressed=true]::after{transform:translateX(20px)}
.tb:focus-visible{outline:2px solid var(--c);outline-offset:3px}
.sbs{display:flex;align-items:center;gap:4px}
.sb{padding:2px 9px;border:1px solid #d1d5db;border-radius:6px;background:#fff;cursor:pointer;font-size:12px;font-weight:700;color:#374151;line-height:1.8}
.sb:hover{background:#f3f4f6}
.sb:focus-visible{outline:2px solid var(--c);outline-offset:2px}
.sv{font-size:11px;color:#6b7280;min-width:26px;text-align:center}
.pf{padding:8px 14px;border-top:1px solid #e5e7eb;text-align:center;font-size:10px;color:#9ca3af;letter-spacing:.02em}
.pf a{color:#9ca3af;text-decoration:none;font-weight:600}
.pf a:hover{color:var(--c)}
`;

function el<K extends keyof HTMLElementTagNameMap>(
  tag: K,
  attrs: Record<string, string> = {},
  cls = ''
): HTMLElementTagNameMap[K] {
  const e = document.createElement(tag);
  if (cls) e.className = cls;
  for (const [k, v] of Object.entries(attrs)) e.setAttribute(k, v);
  return e;
}

export function mountToolbar(shadow: ShadowRoot, config: WidgetConfig): void {
  const color = config.color || '#7c6aff';
  const isTop  = config.position.startsWith('top');
  const isLeft = config.position.endsWith('left');

  // Inject styles
  const style = document.createElement('style');
  style.textContent = CSS;
  shadow.appendChild(style);

  const wrapper = el('div', {}, 'w');
  wrapper.style.setProperty('--c', color);

  // FAB
  const fab = el('button', {
    'aria-label':    'Accessibility options',
    'aria-expanded': 'false',
    'aria-haspopup': 'true',
  }, 'fab');
  fab.style.background = color;
  fab.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="26" height="26" fill="#fff" aria-hidden="true"><circle cx="12" cy="3.5" r="2"/><path d="M17 7.5H7a1 1 0 0 0 0 2h3.5v3L8 17.5a1 1 0 0 0 1.8.9L12 14l2.2 4.4a1 1 0 0 0 1.8-.9L13.5 12.5v-3H17a1 1 0 0 0 0-2z"/></svg>';

  // Panel
  const panel = el('div', { role: 'dialog', 'aria-label': 'Accessibility toolbar' }, 'panel hidden');
  panel.style.cssText = [
    isTop  ? 'top:60px'    : 'bottom:60px',
    isLeft ? 'left:0'      : 'right:0',
  ].join(';');

  // Panel header
  const header = el('div', {}, 'ph');
  const title  = el('span', {}, 'pt');
  title.textContent = 'Accessibility';
  title.style.color = color;
  const closeBtn = el('button', { 'aria-label': 'Close accessibility panel' }, 'xb');
  closeBtn.textContent = '✕';
  header.appendChild(title);
  header.appendChild(closeBtn);
  panel.appendChild(header);

  // Feature list
  const featureList = el('div', {}, 'fs');
  panel.appendChild(featureList);

  // Footer
  if (!config.hide_powered_by) {
    const footer = el('div', {}, 'pf');
    footer.innerHTML = 'Powered by <a href="https://accessai.com" target="_blank" rel="noopener noreferrer">AccessMate</a>';
    panel.appendChild(footer);
  }

  wrapper.appendChild(fab);
  wrapper.appendChild(panel);
  shadow.appendChild(wrapper);

  // ── State ──────────────────────────────────────────────────
  const prefs      = load();
  const state: ToggleState = {};
  const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

  // ── Build feature controls ─────────────────────────────────
  for (const id of config.features) {
    const label = FEATURE_LABELS[id];
    if (!label) continue;

    const row = el('div', {}, 'fr');
    const ico = el('span', { 'aria-hidden': 'true' }, 'fi');
    ico.textContent = FEATURE_ICONS[id] ?? '●';
    const lbl = el('span', {}, 'fl');
    lbl.textContent = label;
    row.appendChild(ico);
    row.appendChild(lbl);

    if (id === 'font') {
      const saved = Number(prefs['font-step'] ?? 0);
      FontSize.setStep(saved);

      const btns  = el('div', {}, 'sbs');
      const decBtn = el('button', { 'aria-label': 'Decrease font size' }, 'sb');
      decBtn.textContent = 'A−';
      const incBtn = el('button', { 'aria-label': 'Increase font size' }, 'sb');
      incBtn.textContent = 'A+';
      const stepVal = el('span', {}, 'sv');
      stepVal.textContent = saved !== 0 ? `${saved > 0 ? '+' : ''}${saved}` : '—';

      decBtn.addEventListener('click', () => {
        FontSize.decrease();
        const s = FontSize.getStep();
        stepVal.textContent = s !== 0 ? `${s > 0 ? '+' : ''}${s}` : '—';
        updatePrefs('font-step', s);
      });
      incBtn.addEventListener('click', () => {
        FontSize.increase();
        const s = FontSize.getStep();
        stepVal.textContent = s !== 0 ? `${s > 0 ? '+' : ''}${s}` : '—';
        updatePrefs('font-step', s);
      });

      btns.appendChild(decBtn);
      btns.appendChild(stepVal);
      btns.appendChild(incBtn);
      row.appendChild(btns);

    } else if (id === 'line-height') {
      const savedIdx = Number(prefs['line-height-step'] ?? 0);
      LineHeight.setStep(savedIdx);
      const LH_LABELS = ['Off', '1.5×', '1.8×', '2.0×'];

      const cycleBtn = el('button', { 'aria-label': 'Cycle line height' }, 'sb');
      cycleBtn.style.minWidth = '44px';
      cycleBtn.textContent = LH_LABELS[savedIdx] ?? 'Off';

      cycleBtn.addEventListener('click', () => {
        const next = LineHeight.cycle();
        const idx  = LineHeight.getStep();
        cycleBtn.textContent = next === 0 ? 'Off' : LH_LABELS[idx] ?? 'Off';
        updatePrefs('line-height-step', idx);
      });

      row.appendChild(cycleBtn);

    } else {
      // Standard toggle
      const savedOn = Boolean(prefs[id]);
      // Respect prefers-reduced-motion for reading-guide
      const startOn = id === 'reading-guide' && reducedMotion ? false : savedOn;
      state[id] = startOn;
      applyFeature(id, startOn);

      // Give the label element a unique id so the toggle button can reference it
      const lblId = `acm-lbl-${id}`;
      lbl.id = lblId;

      const btn = el('button', {
        'aria-pressed':    startOn ? 'true' : 'false',
        'aria-label':      `${startOn ? 'Disable' : 'Enable'} ${label}`,
        'aria-labelledby': lblId,
      }, 'tb');

      btn.addEventListener('click', () => {
        state[id] = !state[id];
        const isOn = state[id];
        btn.setAttribute('aria-pressed', isOn ? 'true' : 'false');
        btn.setAttribute('aria-label', `${isOn ? 'Disable' : 'Enable'} ${label}`);
        applyFeature(id, isOn);
        updatePrefs(id, isOn);
      });

      row.appendChild(btn);

      // Make the entire row clickable — clicking the icon or label triggers
      // the toggle button, but we skip the event when it already originates
      // from the button itself to avoid double-firing.
      row.classList.add('fr-toggle');
      row.setAttribute('role', 'group');
      row.setAttribute('aria-label', label);
      row.addEventListener('click', (e: MouseEvent) => {
        if (e.target === btn || btn.contains(e.target as Node)) return;
        btn.click();
      });

      // Also allow Space / Enter on the row itself for keyboard users who
      // tab to it before reaching the inner button.
      row.setAttribute('tabindex', '-1'); // not in tab order itself; btn already is
    }

    featureList.appendChild(row);
  }

  // ── Panel toggle ────────────────────────────────────────────
  const openPanel = () => {
    panel.classList.remove('hidden');
    fab.setAttribute('aria-expanded', 'true');
    closeBtn.focus();
  };
  const closePanel = () => {
    panel.classList.add('hidden');
    fab.setAttribute('aria-expanded', 'false');
    fab.focus();
  };

  fab.addEventListener('click', () => {
    panel.classList.contains('hidden') ? openPanel() : closePanel();
  });
  closeBtn.addEventListener('click', closePanel);

  // Close on outside click (clicks outside the shadow host)
  document.addEventListener('click', (e: MouseEvent) => {
    if (panel.classList.contains('hidden')) return;
    if (!shadow.host.contains(e.target as Node)) closePanel();
  });

  // Close on Escape key
  panel.addEventListener('keydown', (e: KeyboardEvent) => {
    if (e.key === 'Escape') closePanel();
  });
}

// ── Helpers ──────────────────────────────────────────────────

function applyFeature(id: string, on: boolean): void {
  switch (id) {
    case 'contrast':       Contrast.toggle(on);   break;
    case 'dyslexia':       Dyslexia.toggle(on);   break;
    case 'grayscale':      Grayscale.toggle(on);  break;
    case 'reading-guide':  ReadGuide.toggle(on);  break;
    case 'animations':     Animations.toggle(on); break;
    case 'cursor':         Cursor.toggle(on);     break;
    case 'links':          Links.toggle(on);      break;
    case 'screen-mask':    ScreenMask.toggle(on); break;
  }
}

function updatePrefs(key: string, val: unknown): void {
  const prefs = load();
  prefs[key]  = val;
  save(prefs);
}
