export type AlertA11yProps = {
  role: 'alert';
  'aria-live': 'assertive' | 'polite';
  'aria-label': string;
};

export function alertLabel(level: string, description: string): AlertA11yProps {
  return {
    role: 'alert',
    'aria-live': level === 'danger' ? 'assertive' : 'polite',
    'aria-label': description,
  };
}

const FOCUSABLE_SELECTOR = [
  'a[href]',
  'button:not([disabled])',
  'input:not([disabled])',
  'select:not([disabled])',
  'textarea:not([disabled])',
  '[tabindex]:not([tabindex="-1"])',
].join(',');

export function getFocusableElements(container: HTMLElement): HTMLElement[] {
  return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(
    element =>
      !element.hasAttribute('disabled') &&
      element.getAttribute('aria-hidden') !== 'true' &&
      element.offsetParent !== null
  );
}

export function trapFocusKeydown(event: KeyboardEvent, container: HTMLElement): void {
  if (event.key !== 'Tab') return;

  const focusable = getFocusableElements(container);
  if (focusable.length === 0) {
    event.preventDefault();
    return;
  }

  const first = focusable[0];
  const last = focusable[focusable.length - 1];

  if (event.shiftKey && document.activeElement === first) {
    event.preventDefault();
    last.focus();
  } else if (!event.shiftKey && document.activeElement === last) {
    event.preventDefault();
    first.focus();
  }
}

export function focusFirstElement(container: HTMLElement, selector = FOCUSABLE_SELECTOR): void {
  const preferred = container.querySelector<HTMLElement>(selector);
  const fallback = getFocusableElements(container)[0];
  (preferred ?? fallback)?.focus();
}

export type ScreenReaderPoliteness = 'assertive' | 'polite';

export function announceToScreenReader(
  message: string,
  politeness: ScreenReaderPoliteness = 'polite'
): void {
  if (typeof document === 'undefined') return;

  const id = `bytelyst-sr-announcer-${politeness}`;
  let announcer = document.getElementById(id);
  if (!announcer) {
    announcer = document.createElement('div');
    announcer.id = id;
    announcer.setAttribute('aria-live', politeness);
    announcer.setAttribute('aria-atomic', 'true');
    announcer.style.position = 'absolute';
    announcer.style.width = '1px';
    announcer.style.height = '1px';
    announcer.style.margin = '-1px';
    announcer.style.padding = '0';
    announcer.style.overflow = 'hidden';
    announcer.style.clip = 'rect(0 0 0 0)';
    announcer.style.whiteSpace = 'nowrap';
    announcer.style.border = '0';
    document.body.appendChild(announcer);
  }

  announcer.textContent = '';
  window.setTimeout(() => {
    if (announcer) {
      announcer.textContent = message;
    }
  }, 10);
}

export type ProgressbarA11yProps = {
  role: 'progressbar';
  'aria-label': string;
  'aria-valuenow': number;
  'aria-valuemin': number;
  'aria-valuemax': number;
  'aria-valuetext': string;
};

export function progressLabel(
  label: string,
  valuePct: number,
  description: string
): ProgressbarA11yProps {
  return {
    role: 'progressbar',
    'aria-label': label,
    'aria-valuenow': valuePct,
    'aria-valuemin': 0,
    'aria-valuemax': 100,
    'aria-valuetext': description,
  };
}

export type AriaLabelOnly = { 'aria-label': string };

export function streakLabel(days: number): AriaLabelOnly {
  return { 'aria-label': `${days} day streak` };
}

export type ButtonA11yProps = {
  'aria-label': string;
  'aria-roledescription'?: string;
};

export function buttonLabel(text: string, hint?: string): ButtonA11yProps {
  return {
    'aria-label': text,
    ...(hint ? { 'aria-roledescription': hint } : {}),
  };
}

export function achievementLabel(name: string, description: string): AriaLabelOnly {
  return { 'aria-label': `Achievement: ${name} — ${description}` };
}

export type TimerA11yProps = {
  'aria-label': string;
  'aria-live': 'polite';
};

export function timerLabel(
  hours: number,
  minutes: number,
  seconds: number,
  status: string
): TimerA11yProps {
  return {
    'aria-label': `Timer: ${hours}h ${minutes}m ${seconds}s, ${status}`,
    'aria-live': 'polite',
  };
}

export type SliderA11yProps = {
  role: 'slider';
  'aria-label': string;
  'aria-valuenow': number;
  'aria-valuemin': number;
  'aria-valuemax': number;
};

export function sliderLabel(
  label: string,
  value: number,
  min: number,
  max: number
): SliderA11yProps {
  return {
    role: 'slider',
    'aria-label': label,
    'aria-valuenow': value,
    'aria-valuemin': min,
    'aria-valuemax': max,
  };
}

function plural(n: number, singular: string, pluralForm: string): string {
  const word = n === 1 ? singular : pluralForm;
  return `${n} ${word}`;
}

/**
 * Spoken-friendly duration from a fractional hour value, e.g. 12 → "12 hours", 1.5 → "1 hour 30 minutes".
 */
export function formatDurationForA11y(hours: number): string {
  const totalMinutes = Math.round(hours * 60);
  const h = Math.floor(totalMinutes / 60);
  const m = totalMinutes % 60;

  if (h === 0 && m === 0) {
    return '0 minutes';
  }
  if (m === 0) {
    return plural(h, 'hour', 'hours');
  }
  if (h === 0) {
    return plural(m, 'minute', 'minutes');
  }
  return `${plural(h, 'hour', 'hours')} ${plural(m, 'minute', 'minutes')}`;
}
