import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators.js";

@customElement("play-episode-button")
export class PlayEpisodeButton extends LitElement {
  @property()
  id = "0";

  @property()
  src = "";

  @property()
  mediaType = "";

  @property()
  title!: string;

  @property()
  podcast!: string;

  @property()
  imageSrc!: string;

  @property()
  playLabel!: string;

  @property()
  playingLabel!: string;

  @property({ attribute: false })
  _castopodAudioPlayer!: HTMLDivElement;

  @property({ attribute: false })
  _audio!: HTMLAudioElement;

  @state()
  isPlaying!: boolean;

  @state()
  _playbackSpeed = 1;

  @state()
  _events = [
    {
      name: "canplay",
      onEvent: (event: Event): void => {
        (event.target as HTMLAudioElement)?.play();
      },
    },
    {
      name: "play",
      onEvent: (): void => {
        this.isPlaying = true;
      },
    },
    {
      name: "pause",
      onEvent: (): void => {
        this.isPlaying = false;
      },
    },
    {
      name: "ratechange",
      onEvent: (event: Event): void => {
        this._playbackSpeed = (event.target as HTMLAudioElement)?.playbackRate;
      },
    },
  ];

  async connectedCallback(): Promise<void> {
    super.connectedCallback();

    await this._elementReady("div[id=castopod-audio-player]");
    await this._elementReady("div[id=castopod-audio-player] audio");

    this._castopodAudioPlayer = document.body.querySelector(
      "div[id=castopod-audio-player]"
    ) as HTMLDivElement;

    this._audio = this._castopodAudioPlayer.querySelector(
      "audio"
    ) as HTMLAudioElement;
  }

  private _elementReady(selector: string) {
    return new Promise((resolve) => {
      const element = document.querySelector(selector);
      if (element) {
        resolve(element);
      }
      new MutationObserver((_, observer) => {
        // Query for elements matching the specified selector
        Array.from(document.querySelectorAll(selector)).forEach((element) => {
          resolve(element);
          //Once we have resolved we don't need the observer anymore.
          observer.disconnect();
        });
      }).observe(document.documentElement, {
        childList: true,
        subtree: true,
      });
    });
  }

  play(): void {
    const currentlyPlayingEpisode = this._castopodAudioPlayer.dataset.episode;

    const isCurrentEpisode = currentlyPlayingEpisode === this.id;

    if (currentlyPlayingEpisode === "-1") {
      this._showPlayer();
    }

    if (isCurrentEpisode) {
      this._audio.play();
    } else {
      const playingEpisodeButton = document.querySelector(
        `play-episode-button[id="${currentlyPlayingEpisode}"]`
      ) as PlayEpisodeButton;
      if (playingEpisodeButton) {
        this._flushLastPlayButton(playingEpisodeButton);
      }

      this._loadEpisode();
    }
  }

  pause(): void {
    this._audio.pause();
  }

  private _showPlayer(): void {
    this._castopodAudioPlayer.style.display = "";
    document.body.classList.add("pb-[105px]", "sm:pb-[52px]");
  }

  private _flushLastPlayButton(playingEpisodeButton: PlayEpisodeButton): void {
    playingEpisodeButton.isPlaying = false;

    for (const event of playingEpisodeButton._events) {
      playingEpisodeButton._audio.removeEventListener(
        event.name,
        event.onEvent,
        false
      );
    }

    this._playbackSpeed = playingEpisodeButton._playbackSpeed;
  }

  private _loadEpisode(): void {
    this._castopodAudioPlayer.dataset.episode = this.id;

    this._audio.src = this.src;
    this._audio.load();
    this._audio.playbackRate = this._playbackSpeed;
    for (const event of this._events) {
      this._audio.addEventListener(event.name, event.onEvent, false);
    }

    const img: HTMLImageElement | null =
      this._castopodAudioPlayer.querySelector("img");

    if (img) {
      img.src = this.imageSrc;
      img.alt = this.title;
    }

    const episodeTitle: HTMLParagraphElement | null =
      this._castopodAudioPlayer.querySelector('p[id="castopod-player-title"]');

    if (episodeTitle) {
      episodeTitle.title = this.title;
      episodeTitle.innerHTML = this.title;
    }

    const podcastTitle: HTMLParagraphElement | null =
      this._castopodAudioPlayer.querySelector(
        'p[id="castopod-player-podcast"]'
      );

    if (podcastTitle) {
      podcastTitle.title = this.podcast;
      podcastTitle.innerHTML = this.podcast;
    }
  }

  static styles = css`
    button {
      background-color: hsl(var(--color-accent-base));
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      padding: 0.5rem 0.5rem;
      font-size: 0.875rem;
      line-height: 1.25rem;
      border: 2px solid transparent;
      border-radius: 9999px;

      box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
    }

    button:hover {
      background-color: hsl(var(--color-accent-hover));
    }

    button:focus {
      outline: none;
      box-shadow:
        0 0 0 2px hsl(var(--color-background-base)),
        0 0 0 4px hsl(var(--color-accent-base));
    }

    button.playing {
      background-color: hsl(var(--color-background-base));
      border: 2px solid hsl(var(--color-accent-base));
    }

    button.playing:hover {
      background-color: hsl(var(--color-background-elevated));
    }

    button.playing svg {
      color: hsl(var(--color-accent-base));
    }

    svg {
      font-size: 1.5rem;
      color: hsl(var(--color-accent-contrast));
    }

    @keyframes spin {
      to {
        transform: rotate(360deg);
      }
    }

    .animate-spin {
      animation: spin 3s linear infinite;
    }
  `;

  render(): TemplateResult<1> {
    return html`<button
      class="${this.isPlaying ? "playing" : ""}"
      @click="${this.isPlaying ? this.pause : this.play}"
      title="${this.isPlaying ? this.playingLabel : this.playLabel}"
    >
      ${this.isPlaying
        ? html`<svg
            class="animate-spin"
            viewBox="0 0 24 24"
            fill="currentColor"
            width="1em"
            height="1em"
          >
            <g>
              <path fill="none" d="M0 0h24v24H0z" />
              <path
                d="M13 9.17A3 3 0 1 0 15 12V2.458c4.057 1.274 7 5.064 7 9.542 0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2c.337 0 .671.017 1 .05v7.12z"
              />
            </g>
          </svg>`
        : html`<svg
            viewBox="0 0 24 24"
            fill="currentColor"
            width="1em"
            height="1em"
          >
            <path fill="none" d="M0 0h24v24H0z" />
            <path
              d="M7.752 5.439l10.508 6.13a.5.5 0 0 1 0 .863l-10.508 6.13A.5.5 0 0 1 7 18.128V5.871a.5.5 0 0 1 .752-.432z"
            />
          </svg>`}
    </button>`;
  }
}