import { PktShadowElement } from '@/base-elements/element'
import { html, PropertyValues } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import type { THeadingLevel, THeadingSize, THeadingWeight } from 'shared-types'

export type TPktHeadingLevel = THeadingLevel
export type TPktHeadingSize = THeadingSize
export type TPktHeadingWeight = THeadingWeight

export interface IPktHeading {
  size?: TPktHeadingSize
  level?: TPktHeadingLevel
  weight?: TPktHeadingWeight
  visuallyHidden?: boolean
  align?: 'start' | 'center' | 'end'
}

export class PktHeading extends PktShadowElement<IPktHeading> implements IPktHeading {
  @property({ type: String, reflect: true }) size: TPktHeadingSize | undefined = undefined
  @property({ type: Number, reflect: true }) level: TPktHeadingLevel = 2
  @property({ type: String, reflect: true }) weight: TPktHeadingWeight | undefined = undefined
  @property({ type: Boolean, reflect: true }) visuallyHidden: boolean = false
  @property({ type: String, reflect: true }) align: 'start' | 'center' | 'end' | undefined =
    undefined

  connectedCallback(): void {
    super.connectedCallback()
    this.setAttribute('role', 'heading')
    this.setAttribute('aria-level', String(this.level))

    this.updateHostClasses()
  }

  attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
    super.attributeChangedCallback(name, _old, value)
    if (name === 'level' && value) {
      this.setLevel(Number(value) as TPktHeadingLevel)
    }
    if (name === 'visuallyHidden') {
      this.visuallyHidden = value !== null && value !== 'false'
    }
    if (name === 'size' || name === 'visuallyHidden' || name === 'align' || name === 'weight') {
      this.updateHostClasses()
    }
  }

  protected updated(_changedProperties: PropertyValues): void {
    super.updated(_changedProperties)
    if (_changedProperties.has('level')) {
      this.setLevel(this.level)

      if (!this.hasAttribute('size')) {
        this.size = this.defaultSizeForLevel
      }
      if (!this.hasAttribute('weight')) {
        this.weight = this.defaultWeightForLevel
      }
    }
    if (
      !this.hasAttribute('size') &&
      (_changedProperties.has('level') || this.size === undefined)
    ) {
      this.size = this.defaultSizeForLevel
    }

    if (
      _changedProperties.has('size') ||
      _changedProperties.has('visuallyHidden') ||
      _changedProperties.has('align') ||
      _changedProperties.has('weight')
    ) {
      this.updateHostClasses()
    }
  }

  private setLevel(level: TPktHeadingLevel): void {
    if (level >= 1 && level <= 6) {
      this.level = level
      this.setAttribute('aria-level', String(level))
    } else {
      console.warn(`Invalid heading level: ${level}. Must be between 1 and 6.`)
    }
  }

  private get defaultSizeForLevel(): TPktHeadingSize {
    switch (this.level) {
      case 1:
        return 'xlarge'
      case 2:
        return 'large'
      case 3:
        return 'medium'
      case 4:
        return 'small'
      case 5:
        return 'xsmall'
      case 6:
        return 'xsmall'
      default:
        return 'medium'
    }
  }

  private get defaultWeightForLevel(): TPktHeadingWeight {
    switch (this.level) {
      case 1:
        return 'regular'
      case 2:
        return 'regular'
      case 3:
        return 'medium'
      case 4:
        return 'medium'
      case 5:
        return 'medium'
      case 6:
        return 'medium'
      default:
        return 'medium'
    }
  }

  private updateHostClasses() {
    // Remove all possible classes first
    this.classList.remove(
      'pkt-heading',
      'pkt-heading--xsmall',
      'pkt-heading--small',
      'pkt-heading--medium',
      'pkt-heading--large',
      'pkt-heading--xlarge',
      'pkt-sr-only',
      'pkt-heading--start',
      'pkt-heading--center',
      'pkt-heading--end',
      'pkt-heading--light',
      'pkt-heading--regular',
      'pkt-heading--medium',
      'pkt-heading--bold',
    )
    // Add current classes
    this.classList.add('pkt-heading')
    if (this.size) this.classList.add(`pkt-heading--${this.size}`)
    if (this.weight) this.classList.add(`pkt-heading--fw-${this.weight}`)
    if (this.visuallyHidden) this.classList.add('pkt-sr-only')
    if (this.align) this.classList.add(`pkt-heading--${this.align}`)
  }

  render() {
    return html`<slot></slot>`
  }
}

try {
  customElement('pkt-heading')(PktHeading)
} catch (e) {
  console.warn('Forsøker å definere <pkt-heading>, men den er allerede definert')
}
