import { consume, type ContextType } from "@lit/context";
import {
  mdiArrowOscillating,
  mdiArrowOscillatingOff,
  mdiFan,
  mdiFanOff,
  mdiPower,
  mdiTuneVariant,
} from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { stateActive } from "../../../common/entity/state_active";
import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-attribute-icon";
import "../../../components/ha-control-select-menu";
import "../../../components/ha-list-item";
import "../../../components/ha-outlined-icon-button";
import { UNAVAILABLE } from "../../../data/entity/entity";
import type { FanEntity } from "../../../data/fan";
import {
  FAN_SPEED_COUNT_MAX_FOR_BUTTONS,
  FanEntityFeature,
  computeFanSpeedCount,
  computeFanSpeedStateDisplay,
} from "../../../data/fan";
import { forwardHaptic } from "../../../data/haptics";
import "../../../state-control/fan/ha-state-control-fan-speed";
import "../../../state-control/ha-state-control-toggle";
import { apiContext, formattersContext } from "../../../data/context";
import "../components/ha-more-info-control-select-container";
import "../components/ha-more-info-state-header";
import { moreInfoControlStyle } from "../components/more-info-control-style";
import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";

@customElement("more-info-fan")
class MoreInfoFan extends LitElement {
  @state()
  @consume({ context: formattersContext, subscribe: true })
  private _formatters!: ContextType<typeof formattersContext>;

  @state()
  @consume({ context: apiContext, subscribe: true })
  private _api!: ContextType<typeof apiContext>;

  @property({ attribute: false }) public stateObj?: FanEntity;

  @state() public _presetMode?: string;

  private _renderPresetModeIcon = (value: string) =>
    html`<ha-attribute-icon
      .stateObj=${this.stateObj}
      attribute="preset_mode"
      .attributeValue=${value}
    ></ha-attribute-icon>`;

  private _renderDirectionIcon = (value: string) =>
    html`<ha-attribute-icon
      .stateObj=${this.stateObj}
      attribute="direction"
      .attributeValue=${value}
    ></ha-attribute-icon>`;

  private _toggle = () => {
    const service = this.stateObj?.state === "on" ? "turn_off" : "turn_on";
    forwardHaptic(this, "light");
    this._api.callService("fan", service, {
      entity_id: this.stateObj!.entity_id,
    });
  };

  private _handleDirection(ev: HaDropdownSelectEvent) {
    const newVal = ev.detail.item.value;
    const oldVal = this.stateObj?.attributes.direction;

    if (!newVal || oldVal === newVal) return;

    this._api.callService("fan", "set_direction", {
      entity_id: this.stateObj!.entity_id,
      direction: newVal,
    });
  }

  private _handlePresetMode(ev: HaDropdownSelectEvent) {
    const newVal = ev.detail.item.value;
    const oldVal = this._presetMode;

    if (!newVal || oldVal === newVal) return;

    this._presetMode = newVal;
    this._api.callService("fan", "set_preset_mode", {
      entity_id: this.stateObj!.entity_id,
      preset_mode: newVal,
    });
  }

  private _handleOscillating(ev: HaDropdownSelectEvent) {
    const newVal = ev.detail.item.value === "true";
    const oldVal = this.stateObj?.attributes.oscillating;

    if (oldVal === newVal) return;

    this._api.callService("fan", "oscillate", {
      entity_id: this.stateObj!.entity_id,
      oscillating: newVal,
    });
  }

  protected updated(changedProps: PropertyValues<this>): void {
    if (changedProps.has("stateObj")) {
      this._presetMode = this.stateObj?.attributes.preset_mode;
    }
  }

  private get _stateOverride() {
    const stateDisplay = this._formatters.formatEntityState(this.stateObj!);

    const positionStateDisplay = computeFanSpeedStateDisplay(
      this.stateObj!,
      this._formatters
    );

    if (positionStateDisplay && stateActive(this.stateObj!)) {
      return positionStateDisplay;
    }
    return stateDisplay;
  }

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

    const supportsSpeed = supportsFeature(
      this.stateObj,
      FanEntityFeature.SET_SPEED
    );

    const supportsDirection = supportsFeature(
      this.stateObj,
      FanEntityFeature.DIRECTION
    );
    const supportsOscillate = supportsFeature(
      this.stateObj,
      FanEntityFeature.OSCILLATE
    );
    const supportsPresetMode = supportsFeature(
      this.stateObj,
      FanEntityFeature.PRESET_MODE
    );

    const supportSpeedPercentage =
      supportsSpeed &&
      computeFanSpeedCount(this.stateObj) > FAN_SPEED_COUNT_MAX_FOR_BUTTONS;

    return html`
      <ha-more-info-state-header
        .stateObj=${this.stateObj}
        .stateOverride=${this._stateOverride}
      ></ha-more-info-state-header>
      <div class="controls">
        ${supportsSpeed
          ? html`
              <ha-state-control-fan-speed .stateObj=${this.stateObj}>
              </ha-state-control-fan-speed>
            `
          : html`
              <ha-state-control-toggle
                .stateObj=${this.stateObj}
                .iconPathOn=${mdiFan}
                .iconPathOff=${mdiFanOff}
              ></ha-state-control-toggle>
            `}
        ${supportSpeedPercentage
          ? html`
              <div class="buttons">
                ${supportSpeedPercentage
                  ? html`
                      <ha-outlined-icon-button
                        .disabled=${this.stateObj.state === UNAVAILABLE}
                        @click=${this._toggle}
                      >
                        <ha-svg-icon .path=${mdiPower}></ha-svg-icon>
                      </ha-outlined-icon-button>
                    `
                  : nothing}
              </div>
            `
          : nothing}
      </div>
      <ha-more-info-control-select-container>
        ${supportsPresetMode && this.stateObj.attributes.preset_modes
          ? html`
              <ha-control-select-menu
                .label=${this._formatters.formatEntityAttributeName(
                  this.stateObj,
                  "preset_mode"
                )}
                .value=${this.stateObj.attributes.preset_mode}
                .disabled=${this.stateObj.state === UNAVAILABLE}
                @wa-select=${this._handlePresetMode}
                .options=${this.stateObj.attributes.preset_modes.map(
                  (mode) => ({
                    value: mode,
                    label: this._formatters.formatEntityAttributeValue(
                      this.stateObj!,
                      "preset_mode",
                      mode
                    ),
                  })
                )}
                .renderIcon=${this._renderPresetModeIcon}
              >
                <ha-svg-icon slot="icon" .path=${mdiTuneVariant}></ha-svg-icon>
              </ha-control-select-menu>
            `
          : nothing}
        ${supportsDirection
          ? html`
              <ha-control-select-menu
                .label=${this._formatters.formatEntityAttributeName(
                  this.stateObj,
                  "direction"
                )}
                .value=${this.stateObj.attributes.direction}
                .disabled=${this.stateObj.state === UNAVAILABLE}
                @wa-select=${this._handleDirection}
                .options=${["forward", "reverse"].map((direction) => ({
                  value: direction,
                  label: this.stateObj
                    ? this._formatters.formatEntityAttributeValue(
                        this.stateObj,
                        "direction",
                        direction
                      )
                    : direction,
                }))}
                .renderIcon=${this._renderDirectionIcon}
              >
                <ha-attribute-icon
                  slot="icon"
                  .stateObj=${this.stateObj}
                  attribute="direction"
                  .attributeValue=${this.stateObj.attributes.direction}
                ></ha-attribute-icon>
              </ha-control-select-menu>
            `
          : nothing}
        ${supportsOscillate
          ? html`
              <ha-control-select-menu
                .label=${this._formatters.formatEntityAttributeName(
                  this.stateObj,
                  "oscillating"
                )}
                .value=${this.stateObj.attributes.oscillating
                  ? "true"
                  : "false"}
                .disabled=${this.stateObj.state === UNAVAILABLE}
                @wa-select=${this._handleOscillating}
                .options=${["true", "false"].map((val) => ({
                  value: val,
                  iconPath:
                    val === "true"
                      ? mdiArrowOscillating
                      : mdiArrowOscillatingOff,
                  label: this.stateObj
                    ? this._formatters.formatEntityAttributeValue(
                        this.stateObj,
                        "oscillating",
                        val === "true"
                      )
                    : val,
                }))}
              >
                <ha-svg-icon
                  slot="icon"
                  .path=${mdiArrowOscillatingOff}
                ></ha-svg-icon>
              </ha-control-select-menu>
            `
          : nothing}
      </ha-more-info-control-select-container>
    `;
  }

  static get styles(): CSSResultGroup {
    return moreInfoControlStyle;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    "more-info-fan": MoreInfoFan;
  }
}
