import type { HassEntity } from "home-assistant-js-websocket";
import type { TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { debounce } from "../common/util/debounce";
import type { HASSDomTargetEvent } from "../common/dom/fire_event";
import "../components/entity/state-info";
import type { HaSlider } from "../components/ha-slider";
import "../components/ha-slider";
import type { HaInput } from "../components/input/ha-input";
import "../components/input/ha-input";
import { UNAVAILABLE } from "../data/entity/entity";
import { setValue } from "../data/input_text";
import type { HomeAssistant } from "../types";

@customElement("state-card-input_number")
class StateCardInputNumber extends LitElement {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @property({ attribute: false }) public stateObj!: HassEntity;

  @property({ attribute: "in-dialog", type: Boolean }) public inDialog = false;

  private _loaded?: boolean;

  private _updated?: boolean;

  private _resizeObserver?: ResizeObserver;

  public connectedCallback(): void {
    super.connectedCallback();
    if (this._updated && !this._loaded) {
      this._initialLoad();
    }
    this._attachObserver();
  }

  public disconnectedCallback(): void {
    super.disconnectedCallback();
    this._resizeObserver?.disconnect();
  }

  protected firstUpdated(): void {
    this._updated = true;
    if (this.isConnected && !this._loaded) {
      this._initialLoad();
    }
    this._attachObserver();
  }

  protected render(): TemplateResult {
    return html`
      <state-info
        .hass=${this.hass}
        .stateObj=${this.stateObj}
        .inDialog=${this.inDialog}
      ></state-info>
      ${
        this.stateObj.attributes.mode === "slider"
          ? html`
              <div class="flex">
                <ha-slider
                  labeled
                  .disabled=${this.stateObj.state === UNAVAILABLE}
                  .step=${Number(this.stateObj.attributes.step)}
                  .min=${Number(this.stateObj.attributes.min)}
                  .max=${Number(this.stateObj.attributes.max)}
                  .value=${this.stateObj.state}
                  @change=${this._selectedValueChanged}
                ></ha-slider>
                <span class="state">
                  ${this.hass.formatEntityState(this.stateObj)}
                </span>
              </div>
            `
          : html`
              <div class="flex state">
                <ha-input
                  .disabled=${this.stateObj.state === UNAVAILABLE}
                  pattern="[0-9]+([\\.][0-9]+)?"
                  .step=${Number(this.stateObj.attributes.step)}
                  .min=${Number(this.stateObj.attributes.min)}
                  .max=${Number(this.stateObj.attributes.max)}
                  .value=${Number(this.stateObj.state).toString()}
                  type="number"
                  @change=${this._selectedValueChanged}
                >
                  ${
                    this.stateObj.attributes.unit_of_measurement
                      ? html`<span slot="end"
                          >${this.stateObj.attributes.unit_of_measurement}</span
                        >`
                      : nothing
                  }
                </ha-input>
              </div>
            `
      }
    `;
  }

  static styles = css`
    :host {
      display: flex;
    }
    .flex {
      display: flex;
      align-items: center;
      justify-content: flex-end;
      flex-grow: 2;
    }
    .state {
      min-width: 45px;
      text-align: end;
    }
    ha-input::part(wa-input) {
      text-align: end;
    }
    ha-slider {
      width: 100%;
      max-width: 200px;
    }
    @media (max-width: 450px) {
      state-info {
        flex-basis: 60%;
      }
    }
  `;

  private async _initialLoad(): Promise<void> {
    this._loaded = true;
    await this.updateComplete;
    this._measureCard();
  }

  private _measureCard() {
    if (!this.isConnected) {
      return;
    }
    const element = this.shadowRoot!.querySelector(".state") as HTMLElement;
    if (!element) {
      return;
    }
    element.hidden = this.clientWidth <= 300;
  }

  private async _attachObserver(): Promise<void> {
    if (!this._resizeObserver) {
      this._resizeObserver = new ResizeObserver(
        debounce(() => this._measureCard(), 250, false)
      );
    }
    if (this.isConnected) {
      this._resizeObserver.observe(this);
    }
  }

  private _selectedValueChanged(
    ev: HASSDomTargetEvent<HaSlider | HaInput>
  ): void {
    const value = String(ev.target.value);
    if (value !== this.stateObj.state) {
      setValue(this.hass!, this.stateObj.entity_id, value);
    }
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "state-card-input_number": StateCardInputNumber;
  }
}
