import {MaterialSymbol} from 'material-symbols';
import {SCIcon} from './icon';
import {
  arrowBackOutline,
  caretDownSharp,
  chevronBackOutline,
  chevronExpand,
  chevronForwardOutline,
  close,
  closeCircle,
  closeSharp,
  ellipsisHorizontal,
  menu,
  menuSharp,
  searchOutline,
  searchSharp,
} from 'ionicons/icons';

const styles = new CSSStyleSheet();
styles.replaceSync(/* css */ `
  :host {
    display: inline-flex;
    align-items: center;
    justify-content: center;

    width: 1em;
    height: 1em;

    font-size: inherit;
    font-variation-settings: 'wght' var(--weight, 400), 'GRAD' var(--grade, 1), 'FILL' var(--fill, 0);

    transition: font-variation-settings 0.2s ease-in-out;

    direction: ltr;
    font-family: 'Material Symbols Rounded';
    font-feature-settings: 'liga';
    font-style: normal;
    line-height: 1;
    text-transform: none;
    text-rendering: optimizelegibility;
    letter-spacing: normal;
    word-wrap: normal;
    white-space: nowrap;

    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
`);

export class IonIconCustomElement extends HTMLElement {
  static observedAttributes = ['name', 'size', 'color', 'weight', 'grade', 'fill'];

  set name(value: MaterialSymbol) {
    this.shadowRoot!.textContent =
      document.querySelector('ion-app.ios') && iosAlias.has(value) ? iosAlias.get(value)! : value;
  }

  set icon(value: string) {
    if (iconMap.has(value)) {
      this.name = iconMap.get(value)!;
    } else {
      this.style.setProperty('color', 'red');
      // @ts-expect-error not assignable
      this.name = '??';
      console.error(
        `The icon "${value}" is missing from the icon map (did Ionic change something?)`,
        '\n\n',
        new Error('...')!.stack,
      );
    }
  }

  set size(value: number | string | 'small' | 'large') {
    switch (value) {
      case 'small': {
        this.style.setProperty('font-size', '1.125rem');
        break;
      }
      case 'large': {
        this.style.setProperty('font-size', '2rem');
        break;
      }
      default: {
        this.style.setProperty('font-size', Number.isNaN(Number(value)) ? value.toString() : `${value}px`);
      }
    }
  }

  set color(
    value:
      | 'primary'
      | 'secondary'
      | 'tertiary'
      | 'success'
      | 'warning'
      | 'danger'
      | 'light'
      | 'medium'
      | 'dark',
  ) {
    this.style.setProperty('color', `var(--ion-color-${value}`);
  }

  set fill(value: boolean | undefined) {
    if (value === undefined) {
      this.style.removeProperty('--fill');
    } else {
      this.style.setProperty('--fill', Boolean(value) ? '1' : '0');
    }
  }

  set weight(value: number | undefined) {
    if (value === undefined) {
      this.style.removeProperty('--weight');
    } else {
      this.style.setProperty('--weight', String(value));
    }
  }

  set grade(value: number | undefined) {
    if (value === undefined) {
      this.style.removeProperty('--grade');
    } else {
      this.style.setProperty('--grade', String(value));
    }
  }

  constructor() {
    super();
    const shadow = this.attachShadow({mode: 'open'});
    shadow.adoptedStyleSheets = [styles];
  }
}

const iosAlias = new Map<MaterialSymbol, MaterialSymbol>([
  [SCIcon.arrow_back, SCIcon.arrow_back_ios],
  [SCIcon.arrow_forward, SCIcon.arrow_forward_ios],
  [SCIcon.share, SCIcon.ios_share],
]);

/**
 * Maps hardcoded icon SVGs to our icon names.
 * Thanks, Ionic.
 */
const iconMap = new Map<string, MaterialSymbol>([
  [arrowBackOutline, SCIcon.arrow_back],
  [chevronBackOutline, SCIcon.arrow_back],
  [chevronForwardOutline, SCIcon.arrow_forward],
  [menu, SCIcon.menu],
  [menuSharp, SCIcon.menu],
  [searchOutline, SCIcon.search],
  [searchSharp, SCIcon.search],
  [chevronExpand, SCIcon.expand_all],
  [caretDownSharp, SCIcon.expand_more],
  [close, SCIcon.close],
  [closeSharp, SCIcon.close],
  [closeCircle, SCIcon.cancel],
  [ellipsisHorizontal, SCIcon.more_horiz],
  ['chevron-down-outline', SCIcon.expand_more],
  ['arrow_back', SCIcon.arrow_back],
]);
