import { animate } from "@lit-labs/motion";

import {
  mdiCheckboxBlankOutline,
  mdiCheckboxMarkedOutline,
  mdiClose,
  mdiDelete,
} from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { isComponentLoaded } from "../../common/config/is_component_loaded";
import { fireEvent } from "../../common/dom/fire_event";
import { deleteImage, getIdFromUrl } from "../../data/image_upload";
import type { MediaPlayerItem } from "../../data/media-player";
import { MediaClassBrowserSettings } from "../../data/media-player";
import {
  browseLocalMediaPlayer,
  isImageUploadMediaSourceContentId,
  isLocalMediaSourceContentId,
  removeLocalMedia,
} from "../../data/media_source";
import { showConfirmationDialog } from "../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../types";
import "../ha-button";
import "../ha-check-list-item";
import "../ha-dialog";
import "../ha-dialog-footer";
import "../ha-dialog-header";
import "../ha-icon-button";
import "../ha-list";
import "../ha-spinner";
import "../ha-svg-icon";
import "../ha-tip";
import "./ha-media-player-browse";
import "./ha-media-upload-button";
import type { MediaManageDialogParams } from "./show-media-manage-dialog";

@customElement("dialog-media-manage")
class DialogMediaManage extends LitElement {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @state() private _currentItem?: MediaPlayerItem;

  @state() private _params?: MediaManageDialogParams;

  @state() private _uploading = false;

  @state() private _deleting = false;

  @state() private _selected = new Set<number>();

  @state() private _open = false;

  @state() private _filteredChildren: MediaPlayerItem[] = [];

  private _filesChanged = false;

  public showDialog(params: MediaManageDialogParams): void {
    this._params = params;
    this._refreshMedia();
    this._open = true;
  }

  public closeDialog() {
    this._open = false;
    return true;
  }

  private _dialogClosed(): void {
    if (this._filesChanged && this._params!.onClose) {
      this._params!.onClose();
    }
    this._params = undefined;
    this._currentItem = undefined;
    this._uploading = false;
    this._deleting = false;
    this._filesChanged = false;
    fireEvent(this, "dialog-closed", { dialog: this.localName });
  }

  protected willUpdate() {
    this._filteredChildren =
      this._currentItem?.children?.filter((child) => !child.can_expand) || [];
    if (this._filteredChildren.length === 0 && this._selected.size !== 0) {
      // When running delete all, sometimes the list can throw off a spurious
      // select event that makes it think that 1 item is still selected. Clear selected
      // if nothing can be selected.
      this._selected = new Set();
    }
  }

  protected render() {
    if (!this._params) {
      return nothing;
    }

    let fileIndex = 0;

    return html`
      <ha-dialog
        .open=${this._open}
        ?prevent-scrim-close=${this._uploading || this._deleting}
        @closed=${this._dialogClosed}
      >
        <ha-dialog-header slot="header">
          ${
            !(this._uploading || this._deleting)
              ? html`<slot name="headerNavigationIcon" slot="navigationIcon">
                  <ha-icon-button
                    data-dialog="close"
                    .label=${this.hass?.localize("ui.common.close") ?? "Close"}
                    .path=${mdiClose}
                  ></ha-icon-button
                ></slot>`
              : nothing
          }
          <h1 class="title" slot="title" id="dialog-box-title">
            ${this.hass.localize(
              "ui.components.media-browser.file_management.title"
            )}
          </h1>
          ${
            this._selected.size === 0
              ? html`<ha-media-upload-button
                  .hass=${this.hass}
                  .currentItem=${this._params.currentItem}
                  @uploading=${this._startUploading}
                  @media-refresh=${this._doneUploading}
                  slot="actionItems"
                ></ha-media-upload-button>`
              : html`<ha-button
                  variant="danger"
                  slot="actionItems"
                  .disabled=${this._deleting}
                  @click=${this._handleDelete}
                >
                  <ha-svg-icon .path=${mdiDelete} slot="start"></ha-svg-icon>
                  ${this.hass.localize(
                    `ui.components.media-browser.file_management.${
                      this._deleting ? "deleting" : "delete"
                    }`,
                    { count: this._selected.size }
                  )}
                </ha-button>`
          }
        </ha-dialog-header>
        ${
          !this._currentItem
            ? html`
                <div class="refresh">
                  <ha-spinner></ha-spinner>
                </div>
              `
            : !this._filteredChildren.length
              ? html`<div class="no-items">
                  <p>
                    ${this.hass.localize(
                      "ui.components.media-browser.file_management.no_items"
                    )}
                  </p>
                  ${
                    this._currentItem?.children?.length
                      ? html`<span class="folders"
                          >${this.hass.localize(
                            "ui.components.media-browser.file_management.folders_not_supported"
                          )}</span
                        >`
                      : ""
                  }
                </div>`
              : html`
                  <div class="buttons" slot="footer">
                    <ha-button
                      appearance="filled"
                      @click=${this._handleDeselectAll}
                      .disabled=${this._selected.size === 0}
                    >
                      <ha-svg-icon
                        .path=${mdiCheckboxBlankOutline}
                        slot="start"
                      ></ha-svg-icon>
                      ${this.hass.localize(
                        `ui.components.media-browser.file_management.deselect_all`
                      )}
                    </ha-button>
                    <ha-button
                      appearance="filled"
                      @click=${this._handleSelectAll}
                      .disabled=${
                        this._selected.size === this._filteredChildren.length
                      }
                    >
                      <ha-svg-icon
                        .path=${mdiCheckboxMarkedOutline}
                        slot="start"
                      ></ha-svg-icon>
                      ${this.hass.localize(
                        `ui.components.media-browser.file_management.select_all`
                      )}
                    </ha-button>
                  </div>
                  <ha-list multi @selected=${this._handleSelected}>
                    ${repeat(
                      this._filteredChildren,
                      (item) => item.media_content_id,
                      (item) => {
                        const icon = html`
                          <ha-svg-icon
                            slot="graphic"
                            .path=${
                              MediaClassBrowserSettings[
                                item.media_class === "directory"
                                  ? item.children_media_class ||
                                    item.media_class
                                  : item.media_class
                              ].icon
                            }
                          ></ha-svg-icon>
                        `;
                        return html`
                          <ha-check-list-item
                            ${animate({
                              id: item.media_content_id,
                              skipInitial: true,
                            })}
                            graphic="icon"
                            .disabled=${this._uploading || this._deleting}
                            .selected=${this._selected.has(fileIndex++)}
                            .item=${item}
                          >
                            ${icon} ${item.title}
                          </ha-check-list-item>
                        `;
                      }
                    )}
                  </ha-list>
                `
        }
        ${
          isComponentLoaded(this.hass.config, "hassio")
            ? html`<ha-tip>
                ${this.hass.localize(
                  "ui.components.media-browser.file_management.tip_media_storage",
                  {
                    storage: html`<a
                      href="/config/storage"
                      @click=${this.closeDialog}
                    >
                      ${this.hass.localize(
                        "ui.components.media-browser.file_management.tip_storage_panel"
                      )}</a
                    >`,
                  }
                )}
              </ha-tip>`
            : nothing
        }
      </ha-dialog>
    `;
  }

  private _handleSelected(ev) {
    this._selected = ev.detail.index;
  }

  private _startUploading() {
    this._uploading = true;
    this._filesChanged = true;
  }

  private _doneUploading() {
    this._uploading = false;
    this._refreshMedia();
  }

  private _handleDeselectAll() {
    if (this._selected.size) {
      this._selected = new Set();
    }
  }

  private _handleSelectAll() {
    this._selected = new Set([...Array(this._filteredChildren.length).keys()]);
  }

  private async _handleDelete() {
    if (
      !(await showConfirmationDialog(this, {
        text: this.hass.localize(
          "ui.components.media-browser.file_management.confirm_delete",
          { count: this._selected.size }
        ),
        warning: true,
      }))
    ) {
      return;
    }
    this._filesChanged = true;
    this._deleting = true;

    const toDelete: MediaPlayerItem[] = [];
    let fileIndex = 0;
    this._currentItem!.children!.forEach((item) => {
      if (item.can_expand) {
        return;
      }
      if (this._selected.has(fileIndex++)) {
        toDelete.push(item);
      }
    });

    try {
      await Promise.all(
        toDelete.map(async (item) => {
          if (isLocalMediaSourceContentId(item.media_content_id)) {
            await removeLocalMedia(this.hass, item.media_content_id);
          } else if (isImageUploadMediaSourceContentId(item.media_content_id)) {
            const media_id = getIdFromUrl(item.media_content_id);
            if (media_id) {
              await deleteImage(this.hass, media_id);
            }
          }
          this._currentItem = {
            ...this._currentItem!,
            children: this._currentItem!.children!.filter((i) => i !== item),
          };
        })
      );
    } finally {
      this._deleting = false;
      this._selected = new Set();
    }
  }

  private async _refreshMedia() {
    this._selected = new Set();
    this._currentItem = undefined;
    this._currentItem = await browseLocalMediaPlayer(
      this.hass,
      this._params!.currentItem.media_content_id
    );
  }

  static get styles(): CSSResultGroup {
    return [
      css`
        ha-dialog {
          --dialog-content-padding: 0;
        }
        ha-dialog-header ha-media-upload-button,
        ha-dialog-header ha-button {
          --mdc-theme-primary: var(--primary-text-color);
          margin: 6px;
          display: block;
        }

        ha-tip {
          margin: 16px;
        }

        .refresh {
          display: flex;
          height: 200px;
          justify-content: center;
          align-items: center;
        }
        .buttons {
          display: flex;
          justify-content: center;
          width: 100%;
        }
        .no-items {
          text-align: center;
          padding: 16px;
        }
        .folders {
          color: var(--secondary-text-color);
          font-style: italic;
        }
        .title {
          font: inherit;
          font-size: inherit;
          margin: inherit;
        }
      `,
    ];
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "dialog-media-manage": DialogMediaManage;
  }
}
