import { html, PropertyValues, TemplateResult } from 'lit'
import { property } from 'lit/decorators.js'
import { ClassInfo, classMap } from 'lit/directives/class-map.js'
import { StyleInfo, styleMap } from 'lit/directives/style-map.js'
import { UiRange } from './Range.js'
import { isDisabled, setDisabled } from '../../../lib/disabled.js'
import { floatConverter } from '../../../lib/AttributeConverters.js'

export default class UiProgress extends UiRange {
  protected secondaryRatioInternal?: number

  get disabled(): boolean {
    return isDisabled(this)
  }

  /**
   * When set, the button is a disabled state.
   * @attribute
   */
  @property({ reflect: true, type: Boolean })
  set disabled(value: boolean) {
    const old = isDisabled(this)
    setDisabled(this, value)
    this.requestUpdate('disabled', old)
  }

  /**
   * The number that represents the current secondary progress.
   * @attr
   */
  @property({ type: Number, converter: floatConverter }) accessor secondaryProgress: number | undefined

  /**
   * Use an indeterminate progress indicator.
   * @attr
   */
  @property({ reflect: true, type: Boolean }) accessor indeterminate: boolean | undefined

  /**
   * @returns The ratio of the secondary progress.
   */
  get secondaryRatio(): number {
    return this.secondaryRatioInternal || 0
  }

  override connectedCallback(): void {
    super.connectedCallback()
    if (!this.hasAttribute('role')) {
      this.setAttribute('role', 'progressbar')
    }
  }

  protected override willUpdate(cp: PropertyValues<this>): void {
    super.willUpdate(cp)
    if (cp.has('secondaryProgress') || cp.has('indeterminate')) {
      this.rangeChanged()
    }
  }

  protected override updated(cp: PropertyValues<this>): void {
    if (cp.has('min')) {
      this.setAttribute('aria-valuemin', String(this.min))
    }
    if (cp.has('max')) {
      this.setAttribute('aria-valuemax', String(this.max))
    }
    if (cp.has('indeterminate') || cp.has('value')) {
      if (this.indeterminate) {
        this.removeAttribute('aria-valuenow')
      } else {
        this.setAttribute('aria-valuenow', String(this.value))
      }
    }
  }

  protected override rangeChanged(): void {
    super.rangeChanged()
    const { secondaryProgress: sp } = this
    if (typeof sp === 'number') {
      const secondary = this.clampValue(sp)
      this.secondaryRatioInternal = this.computeRatio(secondary) * 100
    } else {
      this.secondaryRatioInternal = undefined
    }
  }

  override render(): TemplateResult {
    const { secondaryRatio = 0, indeterminate = false, ratio = 0, disabled = false } = this
    const primaryClasses = {
      primary: true,
      indeterminate: !disabled && indeterminate,
      linear: !indeterminate,
    }
    const primaryStyle: StyleInfo = {}
    if (!indeterminate) {
      primaryStyle.transform = `scaleX(${ratio / 100})`
    }
    const secondaryStyle = {
      transform: `scaleX(${secondaryRatio / 100})`,
    }
    const containerClasses: ClassInfo = {
      container: true,
      disabled,
    }
    return html`
      <div class="${classMap(containerClasses)}">
        <div class="secondary" ?hidden="${secondaryRatio === 0}" style="${styleMap(secondaryStyle)}"></div>
        <div class="${classMap(primaryClasses)}" style="${styleMap(primaryStyle)}"></div>
      </div>
    `
  }
}
