import {
  customElement,
  DeesElement,
  type TemplateResult,
  html,
  property,
  css,
  cssManager,
  state,
} from '@design.estate/dees-element';
import { DeesIcon } from '@design.estate/dees-catalog';
import { demo } from './eco-applauncher-keyboard.demo.js';

// Ensure components are registered
DeesIcon;

declare global {
  interface HTMLElementTagNameMap {
    'eco-applauncher-keyboard': EcoApplauncherKeyboard;
  }
}

export type TKeyboardLayout = 'qwerty' | 'numbers' | 'symbols';

export interface IKeyConfig {
  key: string;
  display?: string;
  width?: number; // multiplier, default 1
  type?: 'char' | 'special' | 'modifier' | 'space' | 'layout';
  action?: string;
}

// Long-press alternatives map
const alternativesMap: Record<string, string[]> = {
  'a': ['à', 'á', 'â', 'ä', 'æ', 'ã', 'å', 'ā'],
  'c': ['ç', 'ć', 'č'],
  'e': ['è', 'é', 'ê', 'ë', 'ē', 'ė', 'ę'],
  'i': ['î', 'ï', 'í', 'ī', 'į', 'ì'],
  'n': ['ñ', 'ń'],
  'o': ['ô', 'ö', 'ò', 'ó', 'œ', 'ø', 'ō', 'õ'],
  's': ['ß', 'ś', 'š'],
  'u': ['û', 'ü', 'ù', 'ú', 'ū'],
  'y': ['ÿ'],
  'z': ['ž', 'ź', 'ż'],
  // Numbers
  '0': ['°', '⁰'],
  '1': ['¹', '½', '⅓'],
  '2': ['²', '⅔'],
  '3': ['³', '¾'],
  // Punctuation
  '-': ['–', '—', '•'],
  '/': ['\\'],
  '$': ['€', '£', '¥', '¢'],
  '&': ['§'],
  '"': ['"', '"', '«', '»'],
  '.': ['…'],
  '?': ['¿'],
  '!': ['¡'],
  "'": ['\u2018', '\u2019', '`'],
};

// Keyboard layouts
const qwertyLayout: IKeyConfig[][] = [
  [
    { key: 'q' }, { key: 'w' }, { key: 'e' }, { key: 'r' }, { key: 't' },
    { key: 'y' }, { key: 'u' }, { key: 'i' }, { key: 'o' }, { key: 'p' },
  ],
  [
    { key: 'a' }, { key: 's' }, { key: 'd' }, { key: 'f' }, { key: 'g' },
    { key: 'h' }, { key: 'j' }, { key: 'k' }, { key: 'l' },
  ],
  [
    { key: 'shift', display: '⇧', width: 1.5, type: 'modifier' },
    { key: 'z' }, { key: 'x' }, { key: 'c' }, { key: 'v' },
    { key: 'b' }, { key: 'n' }, { key: 'm' },
    { key: 'backspace', display: '⌫', width: 1.5, type: 'special' },
  ],
  [
    { key: '123', display: '123', width: 1.5, type: 'layout', action: 'numbers' },
    { key: 'globe', display: '🌐', type: 'special' },
    { key: 'space', display: '', width: 3, type: 'space' },
    { key: 'left', display: '←', type: 'special', action: 'arrow-left' },
    { key: 'up', display: '↑', type: 'special', action: 'arrow-up' },
    { key: 'down', display: '↓', type: 'special', action: 'arrow-down' },
    { key: 'right', display: '→', type: 'special', action: 'arrow-right' },
    { key: 'enter', display: '↵', width: 1.5, type: 'special' },
  ],
];

const numbersLayout: IKeyConfig[][] = [
  [
    { key: '1' }, { key: '2' }, { key: '3' }, { key: '4' }, { key: '5' },
    { key: '6' }, { key: '7' }, { key: '8' }, { key: '9' }, { key: '0' },
  ],
  [
    { key: '-' }, { key: '/' }, { key: ':' }, { key: ';' }, { key: '(' },
    { key: ')' }, { key: '$' }, { key: '&' }, { key: '@' }, { key: '"' },
  ],
  [
    { key: '#+=', display: '#+=' , width: 1.5, type: 'layout', action: 'symbols' },
    { key: '.' }, { key: ',' }, { key: '?' }, { key: '!' }, { key: "'" },
    { key: 'backspace', display: '⌫', width: 2.5, type: 'special' },
  ],
  [
    { key: 'ABC', display: 'ABC', width: 1.5, type: 'layout', action: 'qwerty' },
    { key: 'globe', display: '🌐', type: 'special' },
    { key: 'space', display: '', width: 3, type: 'space' },
    { key: 'left', display: '←', type: 'special', action: 'arrow-left' },
    { key: 'up', display: '↑', type: 'special', action: 'arrow-up' },
    { key: 'down', display: '↓', type: 'special', action: 'arrow-down' },
    { key: 'right', display: '→', type: 'special', action: 'arrow-right' },
    { key: 'enter', display: '↵', width: 1.5, type: 'special' },
  ],
];

const symbolsLayout: IKeyConfig[][] = [
  [
    { key: '[' }, { key: ']' }, { key: '{' }, { key: '}' }, { key: '#' },
    { key: '%' }, { key: '^' }, { key: '*' }, { key: '+' }, { key: '=' },
  ],
  [
    { key: '_' }, { key: '\\' }, { key: '|' }, { key: '~' }, { key: '<' },
    { key: '>' }, { key: '€' }, { key: '£' }, { key: '¥' }, { key: '•' },
  ],
  [
    { key: '123', display: '123', width: 1.5, type: 'layout', action: 'numbers' },
    { key: '.' }, { key: ',' }, { key: '?' }, { key: '!' }, { key: "'" },
    { key: 'backspace', display: '⌫', width: 2.5, type: 'special' },
  ],
  [
    { key: 'ABC', display: 'ABC', width: 1.5, type: 'layout', action: 'qwerty' },
    { key: 'globe', display: '🌐', type: 'special' },
    { key: 'space', display: '', width: 3, type: 'space' },
    { key: 'left', display: '←', type: 'special', action: 'arrow-left' },
    { key: 'up', display: '↑', type: 'special', action: 'arrow-up' },
    { key: 'down', display: '↓', type: 'special', action: 'arrow-down' },
    { key: 'right', display: '→', type: 'special', action: 'arrow-right' },
    { key: 'enter', display: '↵', width: 1.5, type: 'special' },
  ],
];

const layouts: Record<TKeyboardLayout, IKeyConfig[][]> = {
  qwerty: qwertyLayout,
  numbers: numbersLayout,
  symbols: symbolsLayout,
};

@customElement('eco-applauncher-keyboard')
export class EcoApplauncherKeyboard extends DeesElement {
  public static demo = demo;
  public static demoGroup = 'App Launcher';

  public static styles = [
    cssManager.defaultStyles,
    css`
      :host {
        display: block;
        width: 100%;
        height: 100%;
      }

      :host(:not([visible])) {
        display: none;
      }

      .keyboard-container {
        background: ${cssManager.bdTheme('hsl(220 15% 92%)', 'hsl(240 6% 12%)')};
        padding: 8px 4px;
        height: 100%;
        display: flex;
        flex-direction: column;
        gap: 6px;
        box-sizing: border-box;
        position: relative;
      }

      .keyboard-row {
        display: flex;
        justify-content: center;
        gap: 4px;
        flex: 1;
      }

      .keyboard-row.offset {
        padding-left: 16px;
      }

      .key {
        flex: 1;
        max-width: 40px;
        height: 100%;
        background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(240 5% 22%)')};
        border-radius: 6px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 18px;
        font-weight: 500;
        color: ${cssManager.bdTheme('hsl(0 0% 10%)', 'hsl(0 0% 95%)')};
        cursor: pointer;
        user-select: none;
        transition: background 0.1s ease, transform 0.05s ease;
        box-shadow: 0 1px 3px ${cssManager.bdTheme('rgba(0, 0, 0, 0.15)', 'rgba(0, 0, 0, 0.4)')};
        text-transform: none;
        -webkit-tap-highlight-color: transparent;
      }

      .key:active,
      .key.pressed {
        transform: scale(0.95);
        background: ${cssManager.bdTheme('hsl(220 15% 92%)', 'hsl(240 5% 28%)')};
      }

      .key.special {
        background: ${cssManager.bdTheme('hsl(220 10% 88%)', 'hsl(240 5% 16%)')};
        font-size: 16px;
      }

      .key.modifier {
        background: ${cssManager.bdTheme('hsl(220 10% 88%)', 'hsl(240 5% 16%)')};
        font-size: 16px;
      }

      .key.modifier.active {
        background: ${cssManager.bdTheme('hsl(217 91% 60%)', 'hsl(217 91% 50%)')};
        color: white;
      }

      .key.layout {
        background: ${cssManager.bdTheme('hsl(220 10% 88%)', 'hsl(240 5% 16%)')};
        font-size: 14px;
        font-weight: 600;
      }

      .key.space {
        background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(240 5% 22%)')};
      }

      .key.wide-1-5 {
        flex: 1.5;
        max-width: 60px;
      }

      .key.wide-2 {
        flex: 2;
        max-width: 80px;
      }

      .key.wide-2-5 {
        flex: 2.5;
        max-width: 100px;
      }

      .key.wide-3 {
        flex: 3;
        max-width: 140px;
      }

      .key.wide-4 {
        flex: 4;
        max-width: 180px;
      }

      /* Alternatives popup */
      .alternatives-popup {
        position: absolute;
        display: flex;
        gap: 2px;
        background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(240 6% 18%)')};
        border-radius: 10px;
        padding: 6px;
        box-shadow: 0 4px 20px ${cssManager.bdTheme('rgba(0, 0, 0, 0.25)', 'rgba(0, 0, 0, 0.6)')};
        z-index: 10000;
        pointer-events: none;
      }

      .alternative-key {
        min-width: 36px;
        height: 44px;
        display: flex;
        align-items: center;
        justify-content: center;
        border-radius: 6px;
        font-size: 20px;
        font-weight: 500;
        color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
        transition: background 0.1s ease;
      }

      .alternative-key.selected {
        background: ${cssManager.bdTheme('hsl(217 91% 60%)', 'hsl(217 91% 50%)')};
        color: white;
      }

      /* Key preview on press */
      .key-preview {
        position: absolute;
        width: 48px;
        height: 56px;
        background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(240 5% 25%)')};
        border-radius: 8px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 24px;
        font-weight: 500;
        color: ${cssManager.bdTheme('hsl(0 0% 10%)', 'hsl(0 0% 95%)')};
        box-shadow: 0 4px 16px ${cssManager.bdTheme('rgba(0, 0, 0, 0.2)', 'rgba(0, 0, 0, 0.5)')};
        z-index: 10000;
        pointer-events: none;
      }
    `,
  ];

  @property({ type: Boolean, reflect: true })
  accessor visible = false;

  @property({ type: String })
  accessor layout: TKeyboardLayout = 'qwerty';

  @state()
  accessor shiftActive = false;

  @state()
  accessor capsLock = false;

  @state()
  accessor alternativesPopup: {
    key: string;
    alternatives: string[];
    x: number;
    y: number;
    selectedIndex: number;
  } | null = null;

  @state()
  accessor keyPreview: { key: string; x: number; y: number } | null = null;

  private longPressTimer: ReturnType<typeof setTimeout> | null = null;
  private longPressStartX = 0;
  private currentLongPressKey: string | null = null;

  public render(): TemplateResult {
    const currentLayout = layouts[this.layout];

    return html`
      <div class="keyboard-container">
        ${currentLayout.map((row, rowIndex) => this.renderRow(row, rowIndex))}
        ${this.alternativesPopup ? this.renderAlternativesPopup() : ''}
        ${this.keyPreview ? this.renderKeyPreview() : ''}
      </div>
    `;
  }

  private renderRow(row: IKeyConfig[], rowIndex: number): TemplateResult {
    const isSecondRow = rowIndex === 1 && this.layout === 'qwerty';
    return html`
      <div class="keyboard-row ${isSecondRow ? 'offset' : ''}">
        ${row.map((keyConfig) => this.renderKey(keyConfig))}
      </div>
    `;
  }

  private renderKey(config: IKeyConfig): TemplateResult {
    const type = config.type || 'char';
    const widthClass = config.width ? `wide-${String(config.width).replace('.', '-')}` : '';
    const isShift = config.key === 'shift';
    const isActive = isShift && (this.shiftActive || this.capsLock);

    let displayValue = config.display ?? config.key;
    if (type === 'char' && this.layout === 'qwerty') {
      displayValue = (this.shiftActive || this.capsLock) ? displayValue.toUpperCase() : displayValue.toLowerCase();
    }

    return html`
      <div
        class="key ${type} ${widthClass} ${isActive ? 'active' : ''}"
        @pointerdown=${(e: PointerEvent) => this.handlePointerDown(e, config)}
        @pointerup=${(e: PointerEvent) => this.handlePointerUp(e, config)}
        @pointerleave=${(e: PointerEvent) => this.handlePointerLeave(e, config)}
        @pointermove=${(e: PointerEvent) => this.handlePointerMove(e, config)}
      >
        ${displayValue}
      </div>
    `;
  }

  private renderAlternativesPopup(): TemplateResult {
    if (!this.alternativesPopup) return html``;

    const { alternatives, x, y, selectedIndex } = this.alternativesPopup;
    const popupWidth = alternatives.length * 40;

    return html`
      <div
        class="alternatives-popup"
        style="left: ${x - popupWidth / 2}px; top: ${y - 60}px;"
      >
        ${alternatives.map((alt, index) => html`
          <div class="alternative-key ${index === selectedIndex ? 'selected' : ''}">
            ${alt}
          </div>
        `)}
      </div>
    `;
  }

  private renderKeyPreview(): TemplateResult {
    if (!this.keyPreview) return html``;

    const { key, x, y } = this.keyPreview;
    return html`
      <div class="key-preview" style="left: ${x - 24}px; top: ${y - 70}px;">
        ${(this.shiftActive || this.capsLock) ? key.toUpperCase() : key}
      </div>
    `;
  }

  private handlePointerDown(e: PointerEvent, config: IKeyConfig): void {
    e.preventDefault();
    const target = e.currentTarget as HTMLElement;
    target.setPointerCapture(e.pointerId);

    const type = config.type || 'char';

    // Show key preview for character keys
    if (type === 'char') {
      const rect = target.getBoundingClientRect();
      const containerRect = this.shadowRoot!.querySelector('.keyboard-container')!.getBoundingClientRect();
      this.keyPreview = {
        key: config.key,
        x: rect.left + rect.width / 2 - containerRect.left,
        y: rect.top - containerRect.top,
      };
    }

    // Start long press timer for keys with alternatives
    const keyLower = config.key.toLowerCase();
    if (alternativesMap[keyLower] && type === 'char') {
      this.longPressStartX = e.clientX;
      this.currentLongPressKey = keyLower;

      this.longPressTimer = setTimeout(() => {
        const alternatives = alternativesMap[keyLower];
        if (alternatives) {
          const rect = target.getBoundingClientRect();
          const containerRect = this.shadowRoot!.querySelector('.keyboard-container')!.getBoundingClientRect();
          this.alternativesPopup = {
            key: keyLower,
            alternatives,
            x: rect.left + rect.width / 2 - containerRect.left,
            y: rect.top - containerRect.top,
            selectedIndex: -1,
          };
          this.keyPreview = null;
        }
      }, 500);
    }
  }

  private handlePointerMove(e: PointerEvent, config: IKeyConfig): void {
    if (this.alternativesPopup) {
      // Calculate which alternative is being hovered based on x position
      const deltaX = e.clientX - this.longPressStartX;
      const alternatives = this.alternativesPopup.alternatives;
      const keyWidth = 40;
      const totalWidth = alternatives.length * keyWidth;
      const startX = -totalWidth / 2;

      // Map deltaX to an index
      const relativeX = deltaX - startX;
      const index = Math.floor(relativeX / keyWidth);
      const clampedIndex = Math.max(-1, Math.min(alternatives.length - 1, index));

      if (clampedIndex !== this.alternativesPopup.selectedIndex) {
        this.alternativesPopup = {
          ...this.alternativesPopup,
          selectedIndex: clampedIndex,
        };
      }
    }
  }

  private handlePointerUp(e: PointerEvent, config: IKeyConfig): void {
    e.preventDefault();
    this.clearLongPressTimer();
    this.keyPreview = null;

    const type = config.type || 'char';

    // Handle alternatives selection
    if (this.alternativesPopup) {
      const { selectedIndex, alternatives, key } = this.alternativesPopup;
      if (selectedIndex >= 0 && selectedIndex < alternatives.length) {
        this.emitKeyPress(alternatives[selectedIndex]);
      } else {
        // No alternative selected, emit original key
        this.emitKeyPress(key);
      }
      this.alternativesPopup = null;
      this.handleShiftAfterKeyPress();
      return;
    }

    // Handle different key types
    switch (type) {
      case 'char':
        const char = (this.shiftActive || this.capsLock)
          ? config.key.toUpperCase()
          : config.key.toLowerCase();
        this.emitKeyPress(char);
        this.handleShiftAfterKeyPress();
        break;

      case 'special':
        this.handleSpecialKey(config);
        break;

      case 'modifier':
        this.handleModifierKey(config);
        break;

      case 'space':
        this.dispatchEvent(new CustomEvent('space', {
          bubbles: true,
          composed: true,
        }));
        this.dispatchEvent(new CustomEvent('key-press', {
          detail: { key: ' ', type: 'space' },
          bubbles: true,
          composed: true,
        }));
        break;

      case 'layout':
        this.handleLayoutChange(config);
        break;
    }
  }

  private handlePointerLeave(e: PointerEvent, config: IKeyConfig): void {
    if (!this.alternativesPopup) {
      this.clearLongPressTimer();
      this.keyPreview = null;
    }
  }

  private clearLongPressTimer(): void {
    if (this.longPressTimer) {
      clearTimeout(this.longPressTimer);
      this.longPressTimer = null;
    }
    this.currentLongPressKey = null;
  }

  private emitKeyPress(key: string): void {
    this.dispatchEvent(new CustomEvent('key-press', {
      detail: { key, type: 'char' },
      bubbles: true,
      composed: true,
    }));
  }

  private handleSpecialKey(config: IKeyConfig): void {
    switch (config.key) {
      case 'backspace':
        this.dispatchEvent(new CustomEvent('backspace', {
          bubbles: true,
          composed: true,
        }));
        this.dispatchEvent(new CustomEvent('key-press', {
          detail: { key: 'Backspace', type: 'special' },
          bubbles: true,
          composed: true,
        }));
        break;

      case 'enter':
        this.dispatchEvent(new CustomEvent('enter', {
          bubbles: true,
          composed: true,
        }));
        this.dispatchEvent(new CustomEvent('key-press', {
          detail: { key: 'Enter', type: 'special' },
          bubbles: true,
          composed: true,
        }));
        break;

      case 'left':
        this.dispatchEvent(new CustomEvent('arrow', {
          detail: { direction: 'left' },
          bubbles: true,
          composed: true,
        }));
        break;

      case 'right':
        this.dispatchEvent(new CustomEvent('arrow', {
          detail: { direction: 'right' },
          bubbles: true,
          composed: true,
        }));
        break;

      case 'up':
        this.dispatchEvent(new CustomEvent('arrow', {
          detail: { direction: 'up' },
          bubbles: true,
          composed: true,
        }));
        break;

      case 'down':
        this.dispatchEvent(new CustomEvent('arrow', {
          detail: { direction: 'down' },
          bubbles: true,
          composed: true,
        }));
        break;

      case 'globe':
        // Could be used for language switching
        this.dispatchEvent(new CustomEvent('globe-press', {
          bubbles: true,
          composed: true,
        }));
        break;
    }
  }

  private handleModifierKey(config: IKeyConfig): void {
    if (config.key === 'shift') {
      if (this.capsLock) {
        // If caps lock is on, turn it off
        this.capsLock = false;
        this.shiftActive = false;
      } else if (this.shiftActive) {
        // Double tap shift = caps lock
        this.capsLock = true;
        this.shiftActive = false;
      } else {
        // Single tap = shift
        this.shiftActive = true;
      }
    }
  }

  private handleShiftAfterKeyPress(): void {
    // Turn off shift after typing (unless caps lock is on)
    if (this.shiftActive && !this.capsLock) {
      this.shiftActive = false;
    }
  }

  private handleLayoutChange(config: IKeyConfig): void {
    const action = config.action as TKeyboardLayout;
    if (action && layouts[action]) {
      this.layout = action;
    }
  }
}
