import { consume } from "@lit/context";
import type { PropertyValues, TemplateResult } from "lit";
import { html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { consumeLocalize } from "../../common/decorators/consume-context-entry";
import { fireEvent } from "../../common/dom/fire_event";
import { stateColorCss } from "../../common/entity/state_color";
import type { LocalizeFunc } from "../../common/translations/localize";
import "../../components/ha-control-button";
import "../../components/ha-control-switch";
import "../../components/ha-state-icon";
import { apiContext } from "../../data/context";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity/entity";
import { forwardHaptic } from "../../data/haptics";
import type { LockEntity } from "../../data/lock";
import { callProtectedLockService } from "../../data/lock";
import {
  stateControlPulseStyle,
  stateControlToggleStyle,
} from "../../resources/state-control-styles";
import type { HomeAssistantApi } from "../../types";

declare global {
  interface HASSDomEvents {
    "lock-service-called": undefined;
  }
}

@customElement("ha-state-control-lock-toggle")
export class HaStateControlLockToggle extends LitElement {
  @state()
  @consume({ context: apiContext, subscribe: true })
  private _api!: HomeAssistantApi;

  @state()
  @consumeLocalize()
  private _localize!: LocalizeFunc;

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

  @state() private _isOn = false;

  public willUpdate(changedProps: PropertyValues<this>): void {
    super.willUpdate(changedProps);
    if (changedProps.has("stateObj")) {
      this._isOn =
        this.stateObj.state === "locked" || this.stateObj.state === "locking";
    }
  }

  private _valueChanged(ev) {
    const checked = ev.target.checked as boolean;

    if (checked) {
      this._turnOn();
    } else {
      this._turnOff();
    }
  }

  private async _turnOn() {
    this._isOn = true;
    try {
      await this._callService(true);
    } catch (_err) {
      this._isOn = false;
    }
  }

  private async _turnOff() {
    this._isOn = false;
    try {
      await this._callService(false);
    } catch (_err) {
      this._isOn = true;
    }
  }

  private async _callService(turnOn: boolean): Promise<void> {
    if (!this.stateObj) {
      return;
    }
    forwardHaptic(this, "light");
    fireEvent(this, "lock-service-called");
    callProtectedLockService(
      this,
      {
        callService: this._api.callService,
        callWS: this._api.callWS,
        localize: this._localize,
      },
      this.stateObj,
      turnOn ? "lock" : "unlock"
    );
  }

  protected render(): TemplateResult {
    const locking = this.stateObj.state === "locking";
    const unlocking = this.stateObj.state === "unlocking";

    const color = stateColorCss(this.stateObj);

    if (this.stateObj.state === UNKNOWN) {
      return html`
        <div class="buttons">
          <ha-control-button
            .label=${this._localize("ui.card.lock.lock")}
            @click=${this._turnOn}
          >
            <ha-state-icon
              .stateObj=${this.stateObj}
              .stateValue=${locking ? "locking" : "locked"}
            ></ha-state-icon>
          </ha-control-button>
          <ha-control-button
            .label=${this._localize("ui.card.lock.unlock")}
            @click=${this._turnOff}
          >
            <ha-state-icon
              .stateObj=${this.stateObj}
              .stateValue=${unlocking ? "unlocking" : "unlocked"}
            ></ha-state-icon>
          </ha-control-button>
        </div>
      `;
    }

    return html`
      <ha-control-switch
        touch-action="none"
        vertical
        reversed
        .checked=${this._isOn}
        @change=${this._valueChanged}
        .label=${this._isOn
          ? this._localize("ui.card.lock.unlock")
          : this._localize("ui.card.lock.lock")}
        style=${styleMap({
          "--control-switch-on-color": color,
          "--control-switch-off-color": color,
        })}
        .disabled=${this.stateObj.state === UNAVAILABLE}
      >
        <ha-state-icon
          slot="icon-on"
          .stateObj=${this.stateObj}
          .stateValue=${locking ? "locking" : "locked"}
          class=${classMap({ pulse: locking })}
        ></ha-state-icon>
        <ha-state-icon
          slot="icon-off"
          .stateObj=${this.stateObj}
          .stateValue=${unlocking ? "unlocking" : "unlocked"}
          class=${classMap({ pulse: unlocking })}
        ></ha-state-icon>
      </ha-control-switch>
    `;
  }

  static styles = [stateControlToggleStyle, stateControlPulseStyle];
}

declare global {
  interface HTMLElementTagNameMap {
    "ha-state-control-lock-toggle": HaStateControlLockToggle;
  }
}
