import { Maybe } from '@/core';
import { ToastService } from '@/core/services/toast.service';
import { UikitLabelComponent } from '@/uikit';
import { UikitFieldComponent } from '@/uikit/uikit-field.component';
import { CommonModule } from '@angular/common';
import {
  Component,
  computed,
  ContentChild,
  EventEmitter,
  inject,
  Input,
  Output,
  TemplateRef,
} from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { InputGroupModule } from 'primeng/inputgroup';
import { InputGroupAddon } from 'primeng/inputgroupaddon';
import { InputMaskModule } from 'primeng/inputmask';
import { InputNumberInputEvent, InputNumberModule } from 'primeng/inputnumber';
import { InputTextModule } from 'primeng/inputtext';
import { KeyFilterModule } from 'primeng/keyfilter';
import { ToggleSwitch } from 'primeng/toggleswitch';

@Component({
  selector: 'app-input',
  standalone: true,
  imports: [
    CommonModule,
    ReactiveFormsModule,
    InputTextModule,
    InputGroupModule,
    UikitFieldComponent,
    ToggleSwitch,
    InputGroupAddon,
    InputNumberModule,
    KeyFilterModule,
    InputMaskModule,
    UikitLabelComponent,
  ],
  templateUrl: './input.component.html',
})
export class InputComponent {
  @Input() type:
    | 'simple'
    | 'postalCode'
    | 'nationalId'
    | 'mobile'
    | 'phone'
    | 'email'
    | 'checkbox'
    | 'switch'
    | 'number'
    | 'price' = 'simple';
  @Input() control!: FormControl<Maybe<any>>;
  @Input() name!: string;
  @Input() label: string = '';
  @Input() placeholder?: string;
  @Input() required = false;
  @Input() disabled = false;
  @Input() size?: 'small' | 'large';
  @Input() autocomplete?: string = 'off';
  @Input() showErrors = true;
  @Input() hint?: string;
  @Input() isLtrInput = false;
  @Input() suffix: string = '';
  @Input() maxLength?: number;
  @Input() min?: number;
  @Input() max?: number;
  @Input() fixed?: number;
  @Input() numericValue?: number;
  @Output() valueChange = new EventEmitter<string | number>();
  @Output() blur = new EventEmitter<void>();

  @ContentChild('suffixTemp', { static: true }) suffixTemp!: TemplateRef<any> | null;
  @ContentChild('labelSuffix', { static: false }) labelSuffix!: TemplateRef<any> | null;
  @ContentChild('labelTextView', { static: false }) labelTextView!: TemplateRef<any> | null;

  private readonly toastService = inject(ToastService);

  // onInput(ev: Event) {
  //   const v = (ev.target as HTMLInputElement).value;

  //   const newLocal = v || v == '0';
  //   // this.valueChange.emit(this.type === 'price' && newLocal ? parseFloat(v) : v);
  // }

  preparedSuffix = computed(() => {
    if (this.type === 'price') {
      return 'ریال';
    } else return this.suffix;
  });

  get preparedPlaceholder(): string | null {
    if (this.placeholder) return this.placeholder;
    switch (this.type) {
      case 'mobile':
        return '09xxxxxxxx';
      case 'postalCode':
        return 'کد پستی (۱۰ رقم)';
      case 'nationalId':
        return 'کد ملی (۱۰ رقم)';
      case 'phone':
        return 'شماره تلفن';
      case 'email':
        return 'آدرس ایمیل خود را وارد کنید';
      case 'price':
        return 'مبلغ';
      default:
        return '';
    }
  }

  get inputMode(): string | null {
    switch (this.type) {
      case 'price':
        return 'decimal';
      case 'number':
      case 'mobile':
      case 'phone':
      case 'postalCode':
      case 'nationalId':
        return 'numeric';
      default:
        return 'text';
    }
  }

  get isNumeric(): boolean {
    return this.inputMode === 'numeric';
  }

  get preparedMaxLength(): number | null {
    switch (this.type) {
      case 'mobile':
        return 11;
      case 'postalCode':
      case 'nationalId':
        return 10;
      case 'phone':
        return 11;
      default:
        return this.maxLength || null;
    }
  }

  get inputClass(): string {
    let inputClass = [];
    switch (this.type) {
      case 'mobile':
      case 'phone':
      case 'price':
      case 'number':
        inputClass.push('ltrInput');
        break;
      case 'email':
      case 'postalCode':
      case 'nationalId':
        inputClass.push('ltrInput', 'rtlPlaceholder');
        break;
    }

    if (this.isLtrInput) {
      inputClass.push('ltrInput', 'rtlPlaceholder');
    }
    return inputClass.join(' ');
  }

  get htmlType(): string {
    switch (this.type) {
      case 'email':
        return 'email';
      case 'mobile':
      case 'phone':
      case 'postalCode':
      case 'nationalId':
        return 'number';
      case 'price':
      case 'number':
        return 'text';
      case 'checkbox':
        return 'checkbox';
      case 'switch':
        return 'radio';
      default:
        return 'text';
    }
  }

  get isRequired(): boolean {
    return this.required || this.control.hasValidator(Validators.required);
  }

  onPriceInput($event: InputNumberInputEvent) {
    this.onInput($event.originalEvent, true);
  }

  private toEnglishDigits(value: string): string {
    return value
      .replace(/[۰-۹]/g, (digit) => String(digit.charCodeAt(0) - 1776))
      .replace(/[٠-٩]/g, (digit) => String(digit.charCodeAt(0) - 1632));
  }

  private sanitizeNumericValue(value: string, allowDecimal: boolean): string {
    const normalized = this.toEnglishDigits(value).replace(/,/g, '');
    const cleaned = normalized.replace(allowDecimal ? /[^0-9.]/g : /[^0-9]/g, '');
    if (!allowDecimal) return cleaned;

    const [integerPart = '', ...decimalParts] = cleaned.split('.');
    const mergedDecimals = decimalParts.join('');
    return decimalParts.length ? `${integerPart}.${mergedDecimals}` : integerPart;
  }

  private applyFixed(value: string): string {
    if (this.fixed === undefined || this.fixed === null || this.fixed < 0 || value === '') {
      return value;
    }

    if (this.fixed === 0) {
      return value.split('.')[0] || '0';
    }

    const [integerPart = '0', decimalPart = ''] = value.split('.');
    const normalizedInteger = integerPart === '' ? '0' : integerPart;
    const fixedDecimal = decimalPart.slice(0, this.fixed).padEnd(this.fixed, '0');
    return `${normalizedInteger}.${fixedDecimal}`;
  }

  onInput($event: Event, isPriceFormat?: boolean) {
    const target = $event.target as HTMLInputElement | null;
    if (!target) return;

    let value = target.value ?? '';
    const allowDecimal = this.type === 'price' || this.type === 'number';

    if (this.inputMode === 'numeric' || this.inputMode === 'decimal' || isPriceFormat) {
      value = this.sanitizeNumericValue(value, allowDecimal);
      value = this.applyFixed(value);
    }

    if (this.preparedMaxLength && value.length > this.preparedMaxLength) {
      value = value.slice(0, this.preparedMaxLength);
    }

    let numericValue = Number.isNaN(parseFloat(value)) ? 0 : parseFloat(value);
    const minValidator = (this.min || this.min === 0) && numericValue < this.min!;
    const maxValidator = (this.max || this.max === 0) && numericValue > this.max!;
    if (
      (this.inputMode === 'numeric' || this.inputMode === 'decimal') &&
      value !== '' &&
      (minValidator || maxValidator)
    ) {
      if (maxValidator) {
        this.toastService.warn({
          text: `مقدار ${this.label} نمی‌تواند بیشتر از ${this.max} باشد.`,
        });
      }
      if (minValidator) {
        this.toastService.warn({
          text: `مقدار ${this.label} نمی‌تواند کمتر از ${this.min} باشد.`,
        });
      }
      value = value.slice(0, -1);
      numericValue = Number.isNaN(parseFloat(value)) ? 0 : parseFloat(value);
    }

    const isIdentifierField = !this.numericValue;
    this.control.setValue(isIdentifierField ? value : value === '' ? '' : numericValue);

    const viewValue = isPriceFormat && value !== '' ? numericValue.toLocaleString('en-US') : value;

    target.value = viewValue;
    if (
      (this.inputMode === 'numeric' || this.inputMode === 'decimal') &&
      this.valueChange.observed
    ) {
      this.valueChange.emit(isIdentifierField ? value : numericValue);
    }
  }
}
