import { css, html, LitElement } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { createRef, ref } from 'lit/directives/ref.js';

import type { TemplateInstance } from '@vouchfor/canvas-video';
import type { MediaPlayer, MediaPlayerProps } from '@vouchfor/media-player';
import type { Vouch } from '@vouchfor/video-utils';
import type { PropertyValueMap } from 'lit';
import type { Environment } from '~/utils/env';

import { EventForwardController } from './controllers/event-forwarder';
import { FetcherController } from './controllers/fetcher';
import { TrackingController } from './controllers/tracking';

import '@vouchfor/media-player';

type PlayerEmbedProps = Pick<MediaPlayerProps, 'aspectRatio' | 'language' | 'preload' | 'autoplay' | 'controls'> & {
  data?: Vouch;
  env: Environment;
  apiKey: string;
  disableTracking?: boolean;
  trackingSource?: string;
  vouchId?: string;
  templateId?: string;
  // Index of the questions to include starting from 1
  questions?: number[];
};

@customElement('vouch-embed-player')
class PlayerEmbed extends LitElement {
  static styles = [
    css`
      :host {
        display: flex;
      }
    `
  ];

  @property({ type: Object }) data: PlayerEmbedProps['data'];
  @property({ type: String }) vouchId: PlayerEmbedProps['vouchId'];
  @property({ type: String }) templateId: PlayerEmbedProps['templateId'];
  @property({ type: Array }) questions: PlayerEmbedProps['questions'];

  @property({ type: String }) env: PlayerEmbedProps['env'] = 'prod';
  @property({ type: String }) apiKey: PlayerEmbedProps['apiKey'] = '';
  @property({ type: Boolean }) disableTracking: PlayerEmbedProps['disableTracking'] = false;
  @property({ type: String }) trackingSource: PlayerEmbedProps['trackingSource'] = 'embedded_player';

  @property({ type: Array }) controls: PlayerEmbedProps['controls'];
  @property({ type: String }) preload: PlayerEmbedProps['preload'] = 'auto';
  @property({ type: Boolean }) autoplay: PlayerEmbedProps['autoplay'] = false;
  @property({ type: Number }) aspectRatio: PlayerEmbedProps['aspectRatio'] = 0;
  @property({ type: String }) language?: MediaPlayerProps['language'];

  private eventController = new EventForwardController(this, [
    'durationchange',
    'ended',
    'error',
    'loadeddata',
    'pause',
    'stalled',
    'play',
    'playing',
    'ratechange',
    'scenechange',
    'scenesupdate',
    'seeking',
    'seeked',
    'timeupdate',
    'volumechange',
    'processing',
    'waiting',

    'video:loadeddata',
    'video:seeking',
    'video:seeked',
    'video:play',
    'video:playing',
    'video:pause',
    'video:stalled',
    'video:timeupdate',
    'video:ended',
    'video:error'
  ]);
  private _fetcherController = new FetcherController(this);
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  private _trackingController = new TrackingController(this);

  @state() vouch: PlayerEmbedProps['data'];
  @state() template: TemplateInstance | undefined;

  get fetching() {
    return this._fetcherController.fetching;
  }

  private _mediaPlayerRef = createRef<MediaPlayer>();

  get waiting() {
    return this._mediaPlayerRef.value?.waiting;
  }

  get initialised() {
    return this._mediaPlayerRef.value?.initialised;
  }

  get seeking() {
    return this._mediaPlayerRef.value?.seeking;
  }

  get paused() {
    return this._mediaPlayerRef.value?.paused;
  }

  get captions() {
    return this._mediaPlayerRef.value?.captions;
  }

  get fullscreen() {
    return this._mediaPlayerRef.value?.fullscreen;
  }

  get duration() {
    return this._mediaPlayerRef.value?.duration;
  }

  set currentTime(value: number) {
    if (this._mediaPlayerRef.value) {
      this._mediaPlayerRef.value.currentTime = value;
    }
  }
  get currentTime() {
    return this._mediaPlayerRef.value?.currentTime ?? 0;
  }

  set playbackRate(value: number) {
    if (this._mediaPlayerRef.value) {
      this._mediaPlayerRef.value.playbackRate = value;
    }
  }
  get playbackRate() {
    return this._mediaPlayerRef.value?.playbackRate ?? 1;
  }

  set volume(value: number) {
    if (this._mediaPlayerRef.value) {
      this._mediaPlayerRef.value.volume = value;
    }
  }
  get volume() {
    return this._mediaPlayerRef.value?.volume ?? 1;
  }

  set muted(value: boolean) {
    if (this._mediaPlayerRef.value) {
      this._mediaPlayerRef.value.muted = value;
    }
  }
  get muted() {
    return this._mediaPlayerRef.value?.muted ?? false;
  }

  // get scene(): Scene | null {
  //   return this._mediaPlayerRef.value?.scene ?? null;
  // }

  // get scenes(): Scene[] {
  //   return this._mediaPlayerRef.value?.scenes ?? [];
  // }

  // get sceneConfig(): Scenes | null {
  //   return this._mediaPlayerRef.value?.sceneConfig ?? null;
  // }

  get mediaState() {
    return this._mediaPlayerRef.value?.mediaState;
  }

  get mediaPlayer() {
    return this._mediaPlayerRef.value;
  }

  play() {
    this._mediaPlayerRef.value?.play();
  }

  pause() {
    this._mediaPlayerRef.value?.pause();
  }

  reset(time = 0, play = false) {
    this._mediaPlayerRef.value?.reset(time, play);
  }

  // setScene(index: number) {
  //   this._mediaPlayerRef.value?.setScene(index);
  // }

  private _renderStyles() {
    if (!this.aspectRatio) {
      return html`
        <style>
          :host {
            width: 100%;
            height: 100%;
          }
        </style>
      `;
    }

    if (typeof this.aspectRatio === 'number') {
      return html`
        <style>
          :host {
            aspect-ratio: ${this.aspectRatio};
          }
        </style>
      `;
    }

    return null;
  }

  protected willUpdate(changedProperties: PropertyValueMap<PlayerEmbedProps>) {
    // If the vouch this embed is pointing to changes then reset the player
    if (changedProperties.has('vouchId') && this.vouchId !== changedProperties.get('vouchId')) {
      this.reset(0, false);
    }
  }

  render() {
    return html`
      ${this._renderStyles()}
      <vmp-media-player
        ${ref(this._mediaPlayerRef)}
        ${this.eventController.register()}
        ?autoplay=${this.autoplay}
        ?loading=${this.fetching}
        aspectRatio=${ifDefined(this.aspectRatio)}
        preload=${ifDefined(this.preload)}
        language=${ifDefined(this.language)}
        .controls=${this.controls}
      ></vmp-media-player>
    `;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'vouch-embed-player': PlayerEmbed;
  }

  namespace JSX {
    interface IntrinsicElements {
      'vouch-embed-player': PlayerEmbed;
    }
  }
}

export { PlayerEmbed };
export type { PlayerEmbedProps };
