import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import { when } from 'lit/directives/when.js';
import { ArxInputChangeEvent } from './Input';

@customElement('arx-textarea')
export class StyledTextarea extends LitElement {
  @property() placeholder = '';
  @property() value = '';
  @property({ type: Boolean }) disabled = false;
  @property() name = '';
  @property({ type: Boolean }) required = false;
  @property() label = '';
  @property() rows = 4;
  @property() maxlength = '';
  @property({ type: Boolean }) resizable = true;

  static override styles = css`
    :host {
      display: block;
      width: 100%;
      margin-bottom: 8px;
    }

    label {
      display: block;
      margin-bottom: 8px;
      font-size: 14px;
      color: var(--color-base-content);
      font-weight: 500;
    }

    textarea {
      width: 100%;
      min-height: 80px;
      padding: 14px 16px;
      font-size: 16px;
      color: var(--color-base-content);
      font-family: inherit;
      line-height: 1.5;
      background: var(--color-base-100);
      border: var(--border) solid var(--color-base-300);
      border-radius: var(--radius-field);
      box-shadow: inset calc(var(--depth) * 2px) calc(var(--depth) * 2px)
          calc(var(--depth) * 4px)
          oklch(from var(--color-base-content) l c h / 0.15),
        inset calc(var(--depth) * -2px) calc(var(--depth) * -2px)
          calc(var(--depth) * 4px) oklch(from var(--color-base-100) l c h / 0.7),
        0 0 0 transparent;
      transition: all 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
      resize: vertical;
    }

    :host(:not([resizable])) textarea {
      resize: none;
    }

    textarea::placeholder {
      color: var(--color-secondary);
      transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1.1);
    }

    textarea:hover {
      transform: translateY(-1px);
      background: oklch(from var(--color-base-100) calc(l + 0.02) c h);
    }

    textarea:hover::placeholder {
      transform: translateX(3px);
    }

    textarea:focus {
      outline: none;
      transform: translateY(1px);
      border-top: var(--border) solid
        oklch(from var(--color-base-300) l c h / 0.8);
      border-left: var(--border) solid
        oklch(from var(--color-base-300) l c h / 0.8);
      border-bottom: var(--border) solid
        oklch(from var(--color-base-200) l c h / 0.8);
      border-right: var(--border) solid
        oklch(from var(--color-base-200) l c h / 0.8);
      box-shadow: inset calc(var(--depth) * 3px) calc(var(--depth) * 3px)
          calc(var(--depth) * 5px)
          oklch(from var(--color-base-content) l c h / 0.2),
        inset calc(var(--depth) * -1px) calc(var(--depth) * -1px)
          calc(var(--depth) * 3px) oklch(from var(--color-base-100) l c h / 0.5),
        0 0 0 transparent;
      background: linear-gradient(
        145deg,
        oklch(from var(--color-base-100) calc(l - 0.03) c h),
        oklch(from var(--color-base-100) l c h)
      );
    }

    textarea:disabled {
      opacity: 0.7;
      cursor: not-allowed;
      box-shadow: inset calc(var(--depth) * 1px) calc(var(--depth) * 1px)
          calc(var(--depth) * 2px)
          oklch(from var(--color-base-content) l c h / 0.05),
        inset calc(var(--depth) * -1px) calc(var(--depth) * -1px)
          calc(var(--depth) * 2px) oklch(from var(--color-base-100) l c h / 0.4);
      transform: none;
    }

    .character-count {
      display: none;
      text-align: right;
      margin-top: 4px;
      font-size: 12px;
      color: var(--color-secondary);
    }

    .has-maxlength .character-count {
      display: block;
    }

    .character-count.near-limit {
      color: var(--color-warning);
    }

    .character-count.at-limit {
      color: var(--color-error);
    }
  `;

  override render() {
    const charCount = this.value?.length || 0;
    const maxLen = Number.parseInt(this.maxlength) || 0;
    const nearLimit = maxLen && charCount >= maxLen * 0.8;
    const atLimit = maxLen && charCount >= maxLen * 0.95;
    const hasMaxlength = !!this.maxlength;

    return html`
      ${when(this.label, () => html`<label for="textarea-${this.name}">${this.label}</label>`)}
      <div class=${classMap({ 'has-maxlength': hasMaxlength })}>
        <textarea
          id="textarea-${this.name}"
          .value=${this.value}
          ?disabled=${this.disabled}
          ?required=${this.required}
          placeholder=${this.placeholder}
          rows=${this.rows}
          .maxlength=${Number.parseInt(this.maxlength) || -1}
          name=${this.name}
          @input=${this._handleInput}
          @focus=${this._handleFocus}
          @blur=${this._handleBlur}
          @keydown=${this._handleKeyDown}
        ></textarea>
        <div
          class="character-count ${nearLimit ? 'near-limit' : ''} ${atLimit ? 'at-limit' : ''}"
        >
          ${charCount}/${this.maxlength}
        </div>
      </div>
    `;
  }

  private _handleKeyDown(e: KeyboardEvent) {
    if (e.key === 'Tab' && !e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) {
      e.preventDefault();
      const textarea = e.target as HTMLTextAreaElement;
      const start = textarea.selectionStart;
      const end = textarea.selectionEnd;

      this.value = `${this.value.substring(0, start)}\t${this.value.substring(end)}`;

      setTimeout(() => {
        textarea.selectionStart = textarea.selectionEnd = start + 1;
      }, 0);
    }

    this.dispatchEvent(
      new CustomEvent('keydown', {
        detail: { key: e.key },
        bubbles: true,
        composed: true,
      }),
    );
  }

  private _handleFocus() {
    this.dispatchEvent(
      new CustomEvent('focus', {
        bubbles: true,
        composed: true,
      }),
    );
  }

  private _handleBlur() {
    this.dispatchEvent(
      new CustomEvent('blur', {
        bubbles: true,
        composed: true,
      }),
    );
  }

  private _handleInput(e: InputEvent) {
    const textarea = e.target as HTMLTextAreaElement;
    this.value = textarea.value;
    this.dispatchEvent(new ArxInputChangeEvent(this.value));
  }
}
