import { mdiDotsVertical, mdiDownload, mdiRefresh, mdiText } from "@mdi/js";
import type { PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import type { HASSDomCurrentTargetEvent } from "../../../common/dom/fire_event";
import type { LocalizeFunc } from "../../../common/translations/localize";
import "../../../components/buttons/ha-call-service-button";
import "../../../components/ha-alert";
import "../../../components/ha-card";
import "../../../components/ha-dropdown";
import "../../../components/ha-dropdown-item";
import "../../../components/ha-icon-button";
import "../../../components/ha-list";
import "../../../components/ha-list-item";
import "../../../components/ha-spinner";
import { getSignedPath } from "../../../data/auth";
import {
  getCoreLogFileDownloadUnavailableReason,
  getErrorLogDownloadUrl,
} from "../../../data/error_log";
import { domainToName } from "../../../data/integration";
import type { LoggedError } from "../../../data/system_log";
import {
  fetchSystemLog,
  getLoggedErrorIntegration,
  isCustomIntegrationError,
} from "../../../data/system_log";
import type { HomeAssistant } from "../../../types";
import { fileDownload } from "../../../util/file_download";
import { showSystemLogDetailDialog } from "./show-dialog-system-log-detail";
import { formatSystemLogTime } from "./util";
import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";

@customElement("system-log-card")
export class SystemLogCard extends LitElement {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @property() public filter = "";

  @property() public header?: string;

  public loaded = false;

  @state() private _items?: LoggedError[];

  public async fetchData(): Promise<void> {
    this._items = undefined;
    this._items = await fetchSystemLog(this.hass!);
  }

  private _timestamp(item: LoggedError): string {
    return formatSystemLogTime(
      item.timestamp,
      this.hass.locale,
      this.hass.config
    );
  }

  private _multipleMessages(item: LoggedError): string {
    return this.hass.localize("ui.panel.config.logs.multiple_messages", {
      time: formatSystemLogTime(
        item.first_occurred,
        this.hass.locale,
        this.hass.config
      ),
      counter: item.count,
    });
  }

  private _getFilteredItems = memoizeOne(
    (localize: LocalizeFunc, items: LoggedError[], filter: string) =>
      items.filter((item: LoggedError) => {
        if (filter) {
          const integration = getLoggedErrorIntegration(item);
          return (
            item.message.some((message: string) =>
              message.toLowerCase().includes(filter)
            ) ||
            item.source[0].toLowerCase().includes(filter) ||
            item.name.toLowerCase().includes(filter) ||
            (integration &&
              domainToName(localize, integration)
                .toLowerCase()
                .includes(filter)) ||
            this._timestamp(item).toLowerCase().includes(filter) ||
            this._multipleMessages(item).toLowerCase().includes(filter)
          );
        }
        return item;
      })
  );

  protected render() {
    const logFileDownloadUnavailableReason =
      getCoreLogFileDownloadUnavailableReason(this.hass);
    const filteredItems = this._items
      ? this._getFilteredItems(
          this.hass.localize,
          this._items,
          this.filter.toLowerCase()
        )
      : [];
    const integrations = filteredItems.length
      ? filteredItems.map((item) => getLoggedErrorIntegration(item))
      : [];
    return html`
      <div class="system-log-intro">
        <ha-card outlined>
          ${
            this._items === undefined
              ? html`
                  <div class="loading-container">
                    <ha-spinner></ha-spinner>
                  </div>
                `
              : html`
                  <div class="header">
                    <h1 class="card-header">
                      ${
                        this.header ||
                        this.hass.localize("ui.panel.config.logs.caption")
                      }
                    </h1>
                    <div class="header-buttons">
                      ${
                        logFileDownloadUnavailableReason
                          ? nothing
                          : html`<ha-icon-button
                              .path=${mdiDownload}
                              @click=${this._downloadLogs}
                              .label=${this.hass.localize(
                                "ui.panel.config.logs.download_logs"
                              )}
                            ></ha-icon-button>`
                      }
                      <ha-icon-button
                        .path=${mdiRefresh}
                        @click=${this.fetchData}
                        .label=${this.hass.localize("ui.common.refresh")}
                      ></ha-icon-button>

                      ${
                        logFileDownloadUnavailableReason
                          ? nothing
                          : html`<ha-dropdown
                              @wa-select=${this._handleOverflowAction}
                            >
                              <ha-icon-button
                                slot="trigger"
                                .path=${mdiDotsVertical}
                                .label=${this.hass.localize("ui.common.menu")}
                              ></ha-icon-button>
                              <ha-dropdown-item value="show-full-logs">
                                <ha-svg-icon
                                  slot="icon"
                                  .path=${mdiText}
                                ></ha-svg-icon>
                                ${this.hass.localize(
                                  "ui.panel.config.logs.show_full_logs"
                                )}
                              </ha-dropdown-item>
                            </ha-dropdown>`
                      }
                    </div>
                  </div>
                  ${
                    logFileDownloadUnavailableReason
                      ? html`<ha-alert alert-type="warning">
                          ${this.hass.localize(
                            `ui.panel.config.logs.log_file_disabled.${logFileDownloadUnavailableReason}`
                          )}
                        </ha-alert>`
                      : nothing
                  }
                  ${
                    this._items.length === 0
                      ? html`
                          <div class="card-content empty-content">
                            ${this.hass.localize("ui.panel.config.logs.no_issues")}
                          </div>
                        `
                      : filteredItems.length === 0 && this.filter
                        ? html`<div class="card-content">
                            ${this.hass.localize(
                              "ui.panel.config.logs.no_issues_search",
                              { term: this.filter }
                            )}
                          </div>`
                        : html`<ha-list
                            >${filteredItems.map(
                              (item, idx) => html`
                                <ha-list-item
                                  @click=${this._openLog}
                                  .logItem=${item}
                                  twoline
                                >
                                  ${item.message[0]}
                                  <span slot="secondary" class="secondary">
                                    ${this._timestamp(item)} –
                                    ${html`(<span class=${item.level}
                                        >${this.hass.localize(
                                          `ui.panel.config.logs.level.${item.level}`
                                        )}</span
                                      >) `}
                                    ${
                                      integrations[idx]
                                        ? `${domainToName(
                                            this.hass!.localize,
                                            integrations[idx]!
                                          )}${
                                            isCustomIntegrationError(item)
                                              ? ` (${this.hass.localize(
                                                  "ui.panel.config.logs.custom_integration"
                                                )})`
                                              : ""
                                          }`
                                        : item.source[0]
                                    }
                                    ${
                                      item.count > 1
                                        ? html`
                                            - ${this._multipleMessages(item)}
                                          `
                                        : nothing
                                    }
                                  </span>
                                </ha-list-item>
                              `
                            )}</ha-list
                          >`
                  }

                  <div class="card-actions">
                    <ha-call-service-button domain="system_log" service="clear"
                      >${this.hass.localize(
                        "ui.panel.config.logs.clear"
                      )}</ha-call-service-button
                    >
                  </div>
                `
          }
        </ha-card>
      </div>
    `;
  }

  protected firstUpdated(changedProps: PropertyValues<this>): void {
    super.firstUpdated(changedProps);
    this.fetchData();
    this.loaded = true;
    this.addEventListener("hass-service-called", (ev) =>
      this.serviceCalled(ev)
    );
  }

  protected serviceCalled(ev): void {
    // Check if this is for us
    if (ev.detail.success && ev.detail.domain === "system_log") {
      // Do the right thing depending on service
      if (ev.detail.service === "clear") {
        this._items = [];
      }
    }
  }

  private _handleOverflowAction(ev: HaDropdownSelectEvent) {
    if (ev.detail.item.value === "show-full-logs") {
      // @ts-ignore
      fireEvent(this, "switch-log-view");
    }
  }

  private async _downloadLogs() {
    if (getCoreLogFileDownloadUnavailableReason(this.hass)) {
      return;
    }

    const timeString = new Date().toISOString().replace(/:/g, "-");
    const downloadUrl = getErrorLogDownloadUrl(this.hass);
    const logFileName = `home-assistant_${timeString}.log`;
    const signedUrl = await getSignedPath(this.hass, downloadUrl);
    fileDownload(signedUrl.path, logFileName);
  }

  private _openLog(
    ev: HASSDomCurrentTargetEvent<HTMLElement & { logItem: LoggedError }>
  ): void {
    const item = (ev.currentTarget as any).logItem;
    showSystemLogDetailDialog(this, { item });
  }

  static styles = css`
    ha-card {
      padding-top: 8px;
    }

    :host {
      direction: var(--direction);
    }
    ha-list {
      direction: ltr;
    }

    .header {
      display: flex;
      justify-content: space-between;
      padding: 0 16px;
    }

    .header-buttons {
      display: flex;
      align-items: flex-start;
    }

    .card-header {
      color: var(--ha-card-header-color, var(--primary-text-color));
      font-family: var(--ha-card-header-font-family, inherit);
      font-size: var(--ha-card-header-font-size, var(--ha-font-size-2xl));
      letter-spacing: -0.012em;
      line-height: var(--ha-line-height-expanded);
      display: block;
      margin-block-start: 0px;
      font-weight: var(--ha-font-weight-normal);
    }

    .system-log-intro {
      margin: 16px;
    }

    .loading-container {
      height: 100px;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .error {
      color: var(--error-color);
    }

    .warning {
      color: var(--warning-color);
    }

    .card-content {
      border-top: 1px solid var(--divider-color);
      padding-top: 16px;
      padding-bottom: 16px;
    }

    .row-secondary {
      text-align: left;
    }
  `;
}

declare global {
  interface HTMLElementTagNameMap {
    "system-log-card": SystemLogCard;
  }
}
