import { mdiPlayBox, mdiPlus } from "@mdi/js";
import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { fireEvent } from "../../common/dom/fire_event";
import { supportsFeature } from "../../common/entity/supports-feature";
import type { MediaPickedEvent } from "../../data/media-player";
import {
  MediaClassBrowserSettings,
  MediaPlayerEntityFeature,
} from "../../data/media-player";
import type { MediaSelector, MediaSelectorValue } from "../../data/selector";
import type { HomeAssistant } from "../../types";
import "../ha-alert";
import "../ha-form/ha-form";
import type { SchemaUnion } from "../ha-form/types";
import "../media-player/ha-media-browser-thumbnail";
import { showMediaBrowserDialog } from "../media-player/show-media-browser-dialog";
import { ensureArray } from "../../common/array/ensure-array";
import "../ha-picture-upload";

const MANUAL_SCHEMA = [
  { name: "media_content_id", required: false, selector: { text: {} } },
  { name: "media_content_type", required: false, selector: { text: {} } },
] as const;

const INCLUDE_DOMAINS = ["media_player"];

const EMPTY_FORM = {};

@customElement("ha-selector-media")
export class HaMediaSelector extends LitElement {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @property({ attribute: false }) public selector!: MediaSelector;

  @property({ attribute: false }) public value?: MediaSelectorValue;

  @property() public label?: string;

  @property() public helper?: string;

  @property({ type: Boolean, reflect: true }) public disabled = false;

  @property({ type: Boolean, reflect: true }) public required = true;

  @property({ attribute: false }) public context?: {
    filter_entity?: string | string[];
  };

  private _contextEntities: string[] | undefined;

  private get _hasAccept(): boolean {
    return !!this.selector?.media?.accept?.length;
  }

  willUpdate(changedProps: PropertyValues<this>) {
    if (changedProps.has("context")) {
      if (!this._hasAccept) {
        this._contextEntities = ensureArray(this.context?.filter_entity);
      }
    }
  }

  protected render() {
    const entityId = this._getActiveEntityId();

    const stateObj = entityId ? this.hass.states[entityId] : undefined;

    const supportsBrowse =
      !entityId ||
      (stateObj &&
        supportsFeature(stateObj, MediaPlayerEntityFeature.BROWSE_MEDIA));

    if (this.selector.media?.image_upload && !this.value) {
      return html`${this.label ? html`<label>${this.label}</label>` : nothing}
        <ha-picture-upload
          .hass=${this.hass}
          .value=${null}
          .contentIdHelper=${this.selector.media?.content_id_helper}
          select-media
          full-media
          @media-picked=${this._pictureUploadMediaPicked}
        ></ha-picture-upload>`;
    }

    return html`
      ${this._hasAccept ||
      (this._contextEntities && this._contextEntities.length <= 1)
        ? nothing
        : html`
            <ha-entity-picker
              .hass=${this.hass}
              .value=${entityId}
              .label=${this.label ||
              this.hass.localize(
                "ui.components.selectors.media.pick_media_player"
              )}
              .disabled=${this.disabled}
              .helper=${this.helper}
              .required=${this.required}
              .hideClearIcon=${!!this._contextEntities}
              .includeDomains=${INCLUDE_DOMAINS}
              .includeEntities=${this._contextEntities}
              .allowCustomEntity=${!this._contextEntities}
              @value-changed=${this._entityChanged}
            ></ha-entity-picker>
          `}
      ${!supportsBrowse
        ? html`
            ${this.label ? html`<label>${this.label}</label>` : nothing}
            <ha-alert>
              ${this.hass.localize(
                "ui.components.selectors.media.browse_not_supported"
              )}
            </ha-alert>
            <ha-form
              .hass=${this.hass}
              .data=${this.value || EMPTY_FORM}
              .schema=${MANUAL_SCHEMA}
              .computeLabel=${this._computeLabelCallback}
              .computeHelper=${this._computeHelperCallback}
            ></ha-form>
          `
        : html`${this.label ? html`<label>${this.label}</label>` : nothing}
            <ha-card
              outlined
              tabindex="0"
              role="button"
              aria-label=${!this.value?.media_content_id
                ? this.hass.localize("ui.components.selectors.media.pick_media")
                : this.value.metadata?.title || this.value.media_content_id}
              @click=${this._pickMedia}
              @keydown=${this._handleKeyDown}
              class=${this.disabled || (!entityId && !this._hasAccept)
                ? "disabled"
                : ""}
            >
              <div class="content-container">
                <div class="thumbnail">
                  ${this.value?.metadata?.thumbnail
                    ? html`
                        <div
                          class="${classMap({
                            "centered-image":
                              !!this.value.metadata.media_class &&
                              ["app", "directory"].includes(
                                this.value.metadata.media_class
                              ),
                          })}
                          image"
                        >
                          <ha-media-browser-thumbnail
                            .hass=${this.hass}
                            .url=${this.value.metadata.thumbnail}
                          ></ha-media-browser-thumbnail>
                        </div>
                      `
                    : html`
                        <div class="icon-holder image">
                          <ha-svg-icon
                            class="folder"
                            .path=${!this.value?.media_content_id
                              ? mdiPlus
                              : this.value?.metadata?.media_class
                                ? MediaClassBrowserSettings[
                                    this.value.metadata.media_class ===
                                    "directory"
                                      ? this.value.metadata
                                          .children_media_class ||
                                        this.value.metadata.media_class
                                      : this.value.metadata.media_class
                                  ].icon
                                : mdiPlayBox}
                          ></ha-svg-icon>
                        </div>
                      `}
                </div>
                <div class="title">
                  ${!this.value?.media_content_id
                    ? this.hass.localize(
                        "ui.components.selectors.media.pick_media"
                      )
                    : this.value.metadata?.title || this.value.media_content_id}
                </div>
              </div>
            </ha-card>
            ${this.selector.media?.clearable
              ? html`<div>
                  <ha-button
                    appearance="plain"
                    size="s"
                    variant="danger"
                    @click=${this._clearValue}
                  >
                    ${this.hass.localize(
                      "ui.components.picture-upload.clear_picture"
                    )}
                  </ha-button>
                </div>`
              : nothing}`}
    `;
  }

  private _computeLabelCallback = (
    schema: SchemaUnion<typeof MANUAL_SCHEMA>
  ): string =>
    this.hass.localize(`ui.components.selectors.media.${schema.name}`);

  private _computeHelperCallback = (
    schema: SchemaUnion<typeof MANUAL_SCHEMA>
  ): string =>
    this.hass.localize(`ui.components.selectors.media.${schema.name}_detail`);

  private _entityChanged(ev: CustomEvent) {
    ev.stopPropagation();
    if (!this._hasAccept && this.context?.filter_entity) {
      fireEvent(this, "value-changed", {
        value: {
          media_content_id: "",
          media_content_type: "",
          metadata: {
            browse_entity_id: ev.detail.value,
          },
        },
      });
    } else {
      fireEvent(this, "value-changed", {
        value: {
          entity_id: ev.detail.value,
          media_content_id: "",
          media_content_type: "",
        },
      });
    }
  }

  private _pickMedia() {
    showMediaBrowserDialog(this, {
      action: "pick",
      entityId: this._getActiveEntityId(),
      navigateIds: this.value?.metadata?.navigateIds,
      accept: this.selector.media?.accept,
      defaultId: this.value?.media_content_id,
      defaultType: this.value?.media_content_type,
      hideContentType: this.selector.media?.hide_content_type,
      contentIdHelper: this.selector.media?.content_id_helper,
      mediaPickedCallback: (pickedMedia: MediaPickedEvent) => {
        fireEvent(this, "value-changed", {
          value: {
            ...this.value,
            media_content_id: pickedMedia.item.media_content_id,
            media_content_type: pickedMedia.item.media_content_type,
            metadata: {
              title: pickedMedia.item.title,
              thumbnail: pickedMedia.item.thumbnail,
              media_class: pickedMedia.item.media_class,
              children_media_class: pickedMedia.item.children_media_class,
              navigateIds: pickedMedia.navigateIds?.map((id) => ({
                media_content_type: id.media_content_type,
                media_content_id: id.media_content_id,
              })),
              ...(!this._hasAccept && this.context?.filter_entity
                ? { browse_entity_id: this._getActiveEntityId() }
                : {}),
            },
          },
        });
      },
    });
  }

  private _getActiveEntityId(): string | undefined {
    const metaId = this.value?.metadata?.browse_entity_id;
    return (
      this.value?.entity_id ||
      (metaId && this._contextEntities?.includes(metaId) && metaId) ||
      this._contextEntities?.[0]
    );
  }

  private _handleKeyDown(ev: KeyboardEvent) {
    if (ev.key === "Enter" || ev.key === " ") {
      ev.preventDefault();
      this._pickMedia();
    }
  }

  private _pictureUploadMediaPicked(ev) {
    const pickedMedia = ev.detail as MediaPickedEvent;
    fireEvent(this, "value-changed", {
      value: {
        ...this.value,
        media_content_id: pickedMedia.item.media_content_id,
        media_content_type: pickedMedia.item.media_content_type,
        metadata: {
          title: pickedMedia.item.title,
          thumbnail: pickedMedia.item.thumbnail,
          media_class: pickedMedia.item.media_class,
          children_media_class: pickedMedia.item.children_media_class,
          navigateIds: pickedMedia.navigateIds?.map((id) => ({
            media_content_type: id.media_content_type,
            media_content_id: id.media_content_id,
          })),
        },
      },
    });
  }

  private _clearValue() {
    fireEvent(this, "value-changed", { value: undefined });
  }

  static styles = css`
    ha-entity-picker {
      display: block;
      margin-bottom: 16px;
    }
    ha-alert {
      display: block;
      margin-bottom: 16px;
    }
    ha-card {
      position: relative;
      width: 100%;
      box-sizing: border-box;
      cursor: pointer;
      transition: background-color 180ms ease-in-out;
      min-height: 56px;
    }
    ha-card:hover:not(.disabled),
    ha-card:focus:not(.disabled) {
      background-color: var(--state-icon-hover-color, rgba(0, 0, 0, 0.04));
    }
    ha-card:focus {
      outline: none;
    }
    ha-card.disabled {
      pointer-events: none;
      color: var(--disabled-text-color);
    }
    .content-container {
      display: flex;
      align-items: center;
      padding: 8px;
      gap: var(--ha-space-3);
    }
    ha-card .thumbnail {
      width: 40px;
      height: 40px;
      flex-shrink: 0;
      position: relative;
      box-sizing: border-box;
      border-radius: var(--ha-border-radius-md);
      overflow: hidden;
    }
    ha-card .image {
      border-radius: var(--ha-border-radius-md);
    }
    .folder {
      --mdc-icon-size: 24px;
    }
    .title {
      font-size: var(--ha-font-size-m);
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      line-height: 1.4;
      flex: 1;
      min-width: 0;
    }
    .image {
      position: absolute;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      --ha-media-browser-thumbnail-fit: cover;
    }
    .centered-image {
      margin: 4px;
      --ha-media-browser-thumbnail-fit: contain;
    }
    .icon-holder {
      display: flex;
      justify-content: center;
      align-items: center;
      width: 100%;
      height: 100%;
    }
  `;
}

declare global {
  interface HTMLElementTagNameMap {
    "ha-selector-media": HaMediaSelector;
  }
}
