import {
  customElement,
  type TemplateResult,
  property,
  state,
  html,
  css,
  cssManager,
} from '@design.estate/dees-element';
import * as domtools from '@design.estate/dees-domtools';
import { DeesInputBase } from '../dees-input-base/dees-input-base.js';
import { demoFunc } from './dees-input-phone.demo.js';
import { themeDefaultStyles } from '../../00theme.js';

declare global {
  interface HTMLElementTagNameMap {
    'dees-input-phone': DeesInputPhone;
  }
}

@customElement('dees-input-phone')
export class DeesInputPhone extends DeesInputBase<DeesInputPhone> {
  // STATIC
  public static demo = demoFunc;
  public static demoGroup = 'Input';

  // INSTANCE
  @state()
  accessor formattedPhone: string = '';

  @property({ type: String })
  accessor value: string = '';

  @property({ type: String })
  accessor placeholder: string = '+1 (555) 123-4567';

  public static styles = [
    themeDefaultStyles,
    ...DeesInputBase.baseStyles,
    cssManager.defaultStyles,
    css`
      /* TODO: Migrate hardcoded values to --dees-* CSS variables */
      /* Phone input specific styles can go here */
    `,
  ];

  public render(): TemplateResult {
    return html`
      <div class="input-wrapper">
        <dees-label .label=${this.label} .description=${this.description}></dees-label>
        <dees-input-text
          .value=${this.formattedPhone}
          .disabled=${this.disabled}
          .required=${this.required}
          .placeholder=${this.placeholder}
          @input=${(event: InputEvent) => this.handlePhoneInput(event)}
        ></dees-input-text>
      </div>
    `;
  }

  public firstUpdated(_changedProperties: Map<string | number | symbol, unknown>) {
    super.firstUpdated(_changedProperties);
    // Initialize formatted phone from value
    if (this.value) {
      this.formattedPhone = this.formatPhoneNumber(this.value);
    }
    
    // Subscribe to the inner input's changes
    const innerInput = this.shadowRoot.querySelector('dees-input-text') as any;
    if (innerInput && innerInput.changeSubject) {
      innerInput.changeSubject.subscribe(() => {
        this.changeSubject.next(this);
      });
    }
  }

  private handlePhoneInput(event: InputEvent) {
    const input = event.target as HTMLInputElement;
    const cleanedValue = this.cleanPhoneNumber(input.value);
    const formatted = this.formatPhoneNumber(cleanedValue);
    
    // Update the input with formatted value
    if (input.value !== formatted) {
      const cursorPosition = input.selectionStart || 0;
      input.value = formatted;
      
      // Try to maintain cursor position intelligently
      const newCursorPos = this.calculateCursorPosition(cleanedValue, formatted, cursorPosition);
      input.setSelectionRange(newCursorPos, newCursorPos);
    }
    
    this.formattedPhone = formatted;
    this.value = cleanedValue;
    this.changeSubject.next(this);
  }

  private cleanPhoneNumber(value: string): string {
    // Remove all non-numeric characters
    return value.replace(/\D/g, '');
  }

  private formatPhoneNumber(value: string): string {
    // Basic US phone number formatting
    // This can be enhanced to support international formats
    const cleaned = this.cleanPhoneNumber(value);
    
    if (cleaned.length === 0) return '';
    if (cleaned.length <= 3) return cleaned;
    if (cleaned.length <= 6) return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3)}`;
    if (cleaned.length <= 10) return `(${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6)}`;
    
    // For numbers longer than 10 digits, format as international
    return `+${cleaned.slice(0, cleaned.length - 10)} (${cleaned.slice(-10, -7)}) ${cleaned.slice(-7, -4)}-${cleaned.slice(-4)}`;
  }

  private calculateCursorPosition(cleaned: string, formatted: string, oldPos: number): number {
    // Simple cursor position calculation
    // Count how many formatting characters are before the cursor
    let formattingChars = 0;
    for (let i = 0; i < oldPos && i < formatted.length; i++) {
      if (!/\d/.test(formatted[i])) {
        formattingChars++;
      }
    }
    return Math.min(oldPos + formattingChars, formatted.length);
  }

  public getValue(): string {
    return this.value;
  }

  public setValue(value: string): void {
    this.value = value;
    this.formattedPhone = this.formatPhoneNumber(value);
  }
}