import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { clamp } from "../../../../../common/number/clamp";
import "../../../../../components/ha-expansion-panel";
import "../../../../../components/ha-select";
import type { HaSelect } from "../../../../../components/ha-select";
import "../../../../../components/input/ha-input";
import type { HaInput } from "../../../../../components/input/ha-input";
import "../../../../../components/item/ha-list-item-base";
import "../../../../../components/item/ha-row-item";
import type { BackupConfig, Retention } from "../../../../../data/backup";
import type { HomeAssistant, ValueChangedEvent } from "../../../../../types";

export type BackupConfigSchedule = Pick<BackupConfig, "schedule" | "retention">;

const MIN_VALUE = 1;
const MAX_VALUE = 9999; // because of input width

export enum RetentionPreset {
  GLOBAL = "global",
  COPIES_3 = "copies_3",
  FOREVER = "forever",
  CUSTOM = "custom",
}

const PRESET_MAP: Record<
  Exclude<RetentionPreset, RetentionPreset.CUSTOM>,
  Retention | null
> = {
  copies_3: { copies: 3, days: null },
  forever: { copies: null, days: null },
  global: null,
};

export interface RetentionData {
  type: "copies" | "days" | "forever";
  value: number;
}

@customElement("ha-backup-config-retention")
class HaBackupConfigRetention extends LitElement {
  @property({ attribute: false }) public hass!: HomeAssistant;

  @property({ attribute: false }) public retention?: Retention | null;

  @property() public headline?: string;

  @property({ type: Boolean, attribute: "location-specific" })
  public locationSpecific = false;

  @state() private _preset: RetentionPreset = RetentionPreset.COPIES_3;

  @state() private _type: "copies" | "days" = "copies";

  @state() private _value = 3;

  @query("#value") private _customValueField?: HaInput;

  @query("#type") private _customTypeField?: HaSelect;

  private _configLoaded = false;

  private presetOptions = [
    RetentionPreset.COPIES_3,
    RetentionPreset.FOREVER,
    RetentionPreset.CUSTOM,
  ];

  public willUpdate() {
    if (!this._configLoaded && this.retention !== undefined) {
      this._configLoaded = true;
      if (!this.retention) {
        this._preset = RetentionPreset.GLOBAL;
      } else if (
        this.retention?.days === null &&
        this.retention?.copies === null
      ) {
        this._preset = RetentionPreset.FOREVER;
      } else {
        this._value = this.retention.copies || this.retention.days || 3;
        if (
          this.retention.days ||
          this.locationSpecific ||
          this.retention.copies !== 3
        ) {
          this._preset = RetentionPreset.CUSTOM;
          this._type = this.retention?.copies ? "copies" : "days";
        }
      }

      if (this.locationSpecific) {
        this.presetOptions = [
          RetentionPreset.GLOBAL,
          RetentionPreset.FOREVER,
          RetentionPreset.CUSTOM,
        ];
      }
    }
  }

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

    return html`
      <ha-list-item-base>
        <span slot="headline">
          ${this.headline ??
          this.hass.localize(`ui.panel.config.backup.schedule.retention`)}
        </span>
        <span slot="supporting-text">
          ${this.hass.localize(
            `ui.panel.config.backup.schedule.retention_description`
          )}
        </span>
        <ha-select
          slot="end"
          @selected=${this._retentionPresetChanged}
          .value=${this._preset}
          .options=${this.presetOptions.map((option) => ({
            value: option,
            label: this.hass.localize(
              `ui.panel.config.backup.schedule.retention_presets.${option}`
            ),
          }))}
        ></ha-select>
      </ha-list-item-base>

      ${this._preset === RetentionPreset.CUSTOM
        ? html`<ha-expansion-panel
            expanded
            .header=${this.hass.localize(
              "ui.panel.config.backup.schedule.custom_retention"
            )}
            outlined
          >
            <ha-row-item>
              <span slot="headline">
                ${this.hass.localize(
                  "ui.panel.config.backup.schedule.custom_retention_label"
                )}
              </span>
              <ha-input
                slot="end"
                @change=${this._retentionValueChanged}
                .value=${this._value.toString()}
                id="value"
                type="number"
                .min=${MIN_VALUE.toString()}
                .max=${MAX_VALUE.toString()}
                step="1"
              >
              </ha-input>
              <ha-select
                slot="end"
                @selected=${this._retentionTypeChanged}
                .value=${this._type}
                id="type"
                .options=${[
                  {
                    value: "days",
                    label: this.hass.localize(
                      "ui.panel.config.backup.schedule.retention_units.days"
                    ),
                  },
                  {
                    value: "copies",
                    label: this.hass.localize(
                      "ui.panel.config.backup.schedule.retention_units.copies"
                    ),
                  },
                ]}
              ></ha-select></ha-row-item
          ></ha-expansion-panel> `
        : nothing}
    `;
  }

  private _retentionPresetChanged(
    ev: ValueChangedEvent<RetentionPreset | undefined>
  ) {
    let value = ev.detail.value;

    if (!value) {
      return;
    }

    if (
      value === RetentionPreset.CUSTOM &&
      (this.locationSpecific || this._preset === RetentionPreset.FOREVER)
    ) {
      this._preset = value;
      // custom needs to have a type of days or copies, set it to default copies 3
      value = RetentionPreset.COPIES_3;
    } else {
      this._preset = value;
    }

    if (this.locationSpecific || value !== RetentionPreset.CUSTOM) {
      const retention = PRESET_MAP[value];

      fireEvent(this, "value-changed", {
        value: retention,
      });
    }
  }

  private _retentionValueChanged(ev) {
    ev.stopPropagation();
    const target = ev.currentTarget as HaInput;
    const value = parseInt(target.value ?? "");
    const clamped = clamp(value, MIN_VALUE, MAX_VALUE);
    target.value = clamped.toString();

    const type = this._customTypeField?.value;

    fireEvent(this, "value-changed", {
      value: {
        copies: type === "copies" ? clamped : null,
        days: type === "days" ? clamped : null,
      },
    });
  }

  private _retentionTypeChanged(
    ev: ValueChangedEvent<"copies" | "days" | undefined>
  ) {
    const type = ev.detail.value;
    if (!type) {
      return;
    }

    this._type = type;

    const value = this._customValueField?.value;

    fireEvent(this, "value-changed", {
      value: {
        copies: type === "copies" ? Number(value) : null,
        days: type === "days" ? Number(value) : null,
      },
    });
  }

  static styles = css`
    ha-row-item,
    ha-list-item-base {
      --ha-row-item-padding-inline: 0;
    }
    ha-row-item::part(end) {
      align-items: flex-start;
    }

    ha-list-item-base::part(headline),
    ha-list-item-base::part(supporting-text) {
      white-space: wrap;
    }
    ha-select {
      min-width: 210px;
    }
    @media all and (max-width: 450px) {
      ha-select {
        min-width: 160px;
        width: 160px;
      }
    }
    ha-input#value {
      min-width: 70px;
    }
    ha-select#type {
      min-width: 100px;
    }
    @media all and (max-width: 450px) {
      ha-input#value {
        min-width: 60px;
        margin: 0 -8px;
      }
      ha-select#type {
        min-width: 120px;
        width: 120px;
      }
    }
    ha-expansion-panel {
      --expansion-panel-summary-padding: 0 16px;
      --expansion-panel-content-padding: 0 16px;
      margin-bottom: 16px;
    }
  `;
}

declare global {
  interface HTMLElementTagNameMap {
    "ha-backup-config-retention": HaBackupConfigRetention;
  }
}
