import { Maybe } from '@/core';
import { ToastService } from '@/core/services/toast.service';
import { UikitFieldComponent, UikitLabelComponent } from '@/uikit';
import { formatWithCurrency } from '@/utils';
import { CommonModule } from '@angular/common';
import {
  ChangeDetectionStrategy,
  Component,
  ContentChild,
  DestroyRef,
  EventEmitter,
  inject,
  Input,
  Output,
  signal,
  TemplateRef,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { InputGroup } from 'primeng/inputgroup';
import { InputGroupAddon } from 'primeng/inputgroupaddon';
import { InputNumberInputEvent, InputNumberModule } from 'primeng/inputnumber';
import { InputText } from 'primeng/inputtext';
import { Select } from 'primeng/select';

type TAmountPercentageInput = 'amount' | 'percentage';
interface IAmountPercentageInputSelect {
  label: string;
  value: TAmountPercentageInput;
}

@Component({
  selector: 'app-amount-percentage-input',
  templateUrl: './amount-percentage-input.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    UikitFieldComponent,
    InputGroup,
    InputGroupAddon,
    ReactiveFormsModule,
    InputText,
    Select,
    InputNumberModule,
    CommonModule,
    UikitLabelComponent,
  ],
})
export class AmountPercentageInputComponent {
  private readonly destroyRef = inject(DestroyRef);
  @Input() defaultType: TAmountPercentageInput = 'percentage';
  @Input({ required: true }) percentageControl!: FormControl<Maybe<any>>;
  @Input({ required: true }) amountControl!: FormControl<Maybe<any>>;
  @Input({ required: true }) name!: string;
  @Input({ required: true }) baseAmount!: number;
  @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() minAmount?: number = 0;
  @Input() maxAmount?: number;
  @Input() minPercentage?: number = 0;
  @Input() maxPercentage?: number = 100;
  @Output() valueChange = new EventEmitter<string | number>();
  @Output() onTypeChange = new EventEmitter<TAmountPercentageInput>();
  @Output() blur = new EventEmitter<void>();

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

  private readonly toastService = inject(ToastService);

  readonly typeSelectOptions: IAmountPercentageInputSelect[] = [
    {
      label: 'قیمت',
      value: 'amount',
    },
    {
      label: 'درصد',
      value: 'percentage',
    },
  ];

  selectedType = new FormControl({
    value: this.defaultType,
    disabled: false,
  });

  preparedLabel = signal(this.label);

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

  onInput($event: Event, isPriceType: boolean = false) {
    // @ts-ignore
    let value = $event.target.value as string;
    // @ts-ignore
    const isDotInput = $event.data === '.';

    if (isDotInput) {
      return;
    }

    if (isPriceType) {
      value = value.replace(/,/g, '');
    }

    const newValueToSet = this.modifyControlsData(value);

    if (newValueToSet !== null) {
      // @ts-ignore
      $event.target.value = newValueToSet;
    }
  }

  private modifyControlsData(value: string) {
    let newValueToSet: Maybe<string> = null;
    let newValue = parseFloat(value);
    const isPercentageType = this.selectedType.value === 'percentage';

    const min = (isPercentageType ? this.minPercentage : this.minAmount) || 0;
    const max = (isPercentageType ? this.maxPercentage : this.maxAmount) || Number.MAX_SAFE_INTEGER;

    const maxValidator = max < newValue;
    const minValidator = min > newValue;

    const notValid = minValidator || maxValidator;

    if (notValid) {
      if (minValidator) {
        this.toastService.warn({
          text: `مقدار ${this.label} باید بیشتر از ${formatWithCurrency(min)} باشد.`,
        });
      }
      if (maxValidator) {
        this.toastService.warn({
          text: `مقدار ${this.label} باید کمتر از ${formatWithCurrency(max)} باشد.`,
        });
      }

      newValue = parseFloat(value.slice(0, value.length - 1));
      if (newValue < 0 || isNaN(newValue)) {
        newValue = 0;
      }
    }

    if (isPercentageType) {
      const amountValue = (this.baseAmount * newValue) / 100;
      newValueToSet = newValue + '';
      this.amountControl.setValue(isNaN(amountValue) ? 0 : amountValue, { emitEvent: false });
      if (notValid) {
        this.percentageControl.setValue(newValue, { emitEvent: false });
      }
    } else {
      const percentageValue = ((newValue / this.baseAmount) * 100).toFixed(2);
      newValueToSet = newValue + '';
      this.percentageControl.setValue(percentageValue, { emitEvent: false });
      this.preparedLabel.set(`${this.label} (${percentageValue} درصد)`);
      if (notValid) {
        this.amountControl.setValue(newValue, { emitEvent: false });
      }
    }
    this.preparedLabel.set(this.prepareLabel(isPercentageType));

    return newValue;
  }

  private prepareLabel(isPercentageType: boolean) {
    if (isPercentageType) {
      return `${this.label} (معادل ${formatWithCurrency(this.amountControl.value || 0)})`;
    }
    return `${this.label} (معادل ${this.percentageControl.value || 0} درصد)`;
  }

  ngOnInit() {
    const amountValue = Number(this.amountControl.value || 0);
    const percentageValue = Number(this.percentageControl.value || 0);
    const isPercentageType = percentageValue > 0 && amountValue <= 0;
    this.preparedLabel.set(this.prepareLabel(isPercentageType));

    this.selectedType.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((value) => {
      this.preparedLabel.set(this.prepareLabel(value === 'percentage'));
    });
  }

  ngOnChanges() {
    const amountValue = Number(this.amountControl.value || 0);
    const percentageValue = Number(this.percentageControl.value || 0);
    const isPercentageType = percentageValue > 0 && amountValue <= 0;
    this.preparedLabel.set(this.prepareLabel(isPercentageType));
  }
}
