import { Component, Inject, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { IServiceConfigOptionModel } from '@fleio-api/billing/model/service-config-option.model';
import {
  ServiceConfigurableOptionApiService
} from '@fleio-api/billing/service-configurable-options/service-configurable-option-api.service';
import { IServiceModel } from '@fleio-api/billing/model/service.model';
import { ConfigurableOptionsApiService } from '@fleio-api/billing/configurable-options/configurable-option-api.service';
import { ProductsApiService } from '@fleio-api/billing/products/product-api.service';
import {
  ConfigurableOptionsChoiceApiService
} from '@fleio-api/billing/configurable-options/configurable-option-choice-api.service';
import { ValidatorsHelper } from '@shared/ui-api/helpers/validators-helper';
import { IProductModel } from '@fleio-api/billing/model/product.model';
import { IBaseDialog } from '@shared/common-dialogs/base-dialog';
import { IAction } from '@objects-view/interfaces/actions/action';
import { DialogCallbackAction } from '@objects-view/actions/dialog-callback-action';
import { IProductCycleModel } from '@fleio-api/billing/model/product-cycle.model';
import { ConfigService } from '@shared/config/config.service';
import { NotificationService } from '@shared/ui-api/notification.service';

@Component({
  selector: 'app-service-configurable-option-edit-dialog',
  templateUrl: './service-configurable-option-edit-dialog.component.html',
  styleUrls: ['./service-configurable-option-edit-dialog.component.scss']
})
export class ServiceConfigurableOptionEditDialogComponent implements IBaseDialog, OnInit {
  @ViewChild('formErrors') formErrors;
  serviceConfigurableOptionForm = this.formBuilder.group({
    display: [''],
    option: ['', [Validators.required, ValidatorsHelper.requiredObjectValidator]],
    option_value: [''],
    quantity: [1, ValidatorsHelper.requiredNumericValueValidator],
    unit_price: ['', ValidatorsHelper.requiredNumericValueValidator],
    price: ['', ValidatorsHelper.requiredNumericValueValidator],
    setup_fee: ['', ValidatorsHelper.requiredNumericValueValidator],
  });
  unitPriceControl = this.serviceConfigurableOptionForm.controls.unit_price;
  priceControl = this.serviceConfigurableOptionForm.controls.price;
  setupFeeControl = this.serviceConfigurableOptionForm.controls.setup_fee;
  dialogTitle = null;
  dialogActions: Array<IAction> = [
    new DialogCallbackAction({
      name: $localize`Save option`,
      primary: true,
      callback: () => this.saveOption(),
    }),
  ];
  dialogForm = this.serviceConfigurableOptionForm;
  createOptions: Record<string, unknown>;
  backendErrors: Record<string, unknown> = {};
  quantityHidden = false;
  optionValueHidden = false;
  loading = false;
  currentOptionId;
  currentOptionValueId = null;
  percentageInPrevOptions = false;
  noMatchingCycle = false;

  optionValues = [];

  constructor(
    public dialogRef: MatDialogRef<ServiceConfigurableOptionEditDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: {
      serviceConfigurableOption: IServiceConfigOptionModel;
      service: IServiceModel;
      serviceSelectedCycle: IProductCycleModel;
      previousOptions;
      product: IProductModel;
    },
    private formBuilder: UntypedFormBuilder,
    private serviceConfigurableOptionApiService: ServiceConfigurableOptionApiService,
    private configurableOptionsApiService: ConfigurableOptionsApiService,
    private productsApiService: ProductsApiService,
    private configurableOptionsChoiceApiService: ConfigurableOptionsChoiceApiService,
    public config: ConfigService,
    private notificationService: NotificationService,
  ) {
  }

  saveOption() {
    if (!this.serviceConfigurableOptionForm.valid) {
      return;
    }
    const value = this.serviceConfigurableOptionForm.value;
    if (value && value.option) {
      value.option = value.option.id;
    }
    value.option_value = value?.option_value?.choice || value.option_value;
    value.option_value_id = this.currentOptionValueId || this.data?.serviceConfigurableOption?.option_value_id || null;
    value.service = this.data.service.id;

    this.loading = true;
    this.dialogRef.close(value);
  }

  setOptionValueChoices(option) {
    let params;
    if (option && option.id) {
      if (option.widget === 'yesno') {
        this.optionValues = ['yes', 'no'];
        return;
      }
      params = {
        option: option.id,
        currency: this.data.service.cycle.currency,
        page_size: 10000000,
      };
      this.configurableOptionsChoiceApiService.list(params).subscribe(value => {
        this.optionValues = value.objects;
      });
    } else {
      this.optionValues = [];
    }
  }

  private updateOptionValueHidden(selectedOption) {
    if (selectedOption.widget !== 'num_in') {
      this.quantityHidden = true;
      this.optionValueHidden = false;
    } else {
      this.quantityHidden = false;
      this.optionValueHidden = true;
    }
  }

  ngOnInit(): void {
    this.dialogTitle = $localize`Edit option`;
    this.serviceConfigurableOptionForm.patchValue(this.data.serviceConfigurableOption, {emitEvent: false});

    this.loading = true;
    const cycleParams = {
      option: this.data.serviceConfigurableOption.option,
      cycle: this.data.serviceSelectedCycle.cycle,
      cycle_multiplier: this.data.serviceSelectedCycle.cycle_multiplier,
      currency: this.data.service.cycle.currency,
    } as any;
    this.configurableOptionsApiService.hasMatchingCycle(
      this.data.serviceConfigurableOption.option,
      JSON.stringify(cycleParams)
    ).subscribe(response => {
      if (!response.has_matching_cycle) {
        this.noMatchingCycle = true;
        this.dialogActions.pop();
      }
    }).add(() => {
      this.loading = false;
    });

    if (this.data?.serviceConfigurableOption) {
      this.currentOptionId = this.data.serviceConfigurableOption.option;
      this.loading = true;
      this.configurableOptionsApiService.get(this.data.serviceConfigurableOption.option).subscribe(value => {
        this.serviceConfigurableOptionForm.controls.option.patchValue(value, {emitEvent: false});
        this.setOptionValueChoices(value);
        this.updateOptionValueHidden(value);
        this.loading = false;
      });
    } else {
      this.setOptionValueChoices(null);
    }

    this.serviceConfigurableOptionForm.controls.quantity.valueChanges.subscribe(quantityValue => {
      const selectedOption = this.serviceConfigurableOptionForm.controls.option.value;
      if (selectedOption && selectedOption.widget === 'num_in') {
        this.serviceConfigurableOptionForm.controls.option_value.setValue(quantityValue);
      }
    });

    this.serviceConfigurableOptionForm.controls.option.valueChanges.subscribe(option => {
      if (option && option.id) {
        this.serviceConfigurableOptionForm.controls.display.setValue(option.display_name);
        this.serviceConfigurableOptionForm.controls.unit_price.setValue(null);
        this.serviceConfigurableOptionForm.controls.price.setValue(null);
        this.updateOptionValueHidden(option);
        // reset quantity to 1 on option select
        this.serviceConfigurableOptionForm.controls.quantity.setValue(1);
        if (this.currentOptionId !== option.id) {
          if (option.widget !== 'num_in') {
            // option value was already reset to 1 for num_in widgets
            this.serviceConfigurableOptionForm.controls.option_value.setValue(null);
          }
          this.currentOptionId = option.id;
        }
        this.setOptionValueChoices(option);
      }
    });

    this.serviceConfigurableOptionForm.controls.option_value.valueChanges.subscribe(value => {
      const option = this.serviceConfigurableOptionForm.controls.option.value;
      let choiceFilter = null;
      if ((option.widget === 'drop' || option.widget === 'radio') && value) {
        choiceFilter = this.optionValues.find(choice => choice.choice === value).id;
      }
      if (option && option.id) {
        const cycleParams = {
          option: option.id,
          cycle: this.data.serviceSelectedCycle.cycle,
          cycle_multiplier: this.data.serviceSelectedCycle.cycle_multiplier,
          currency: this.data.service.cycle.currency,
        } as any;
        if (choiceFilter === null) {
          cycleParams.value__isnull = true;
        } else {
          cycleParams.value = choiceFilter;
        }
        const quantity = this.serviceConfigurableOptionForm.contains('quantity') ?
          this.serviceConfigurableOptionForm.controls.quantity.value : null;

        this.configurableOptionsApiService.getOptionPrice(
          option.id,
          this.data.service.cycle.currency,
          JSON.stringify(cycleParams),
          value?.choice || value,
          JSON.stringify(this.data.previousOptions),
          this.data.service.id,
          quantity,
        ).subscribe({
          next: response => {
            this.currentOptionValueId = response.option_value_id;
            this.percentageInPrevOptions = response.percentage_in_prev_options;
            if (typeof response.unit_price === 'number') {
              this.serviceConfigurableOptionForm.controls.unit_price.setValue(response.unit_price);
            }
            if (option.widget === 'yesno' && value === 'no') {
              // yesno option with no value is set with 0 price
              this.serviceConfigurableOptionForm.controls.price.setValue(0);
            } else if (typeof response.price === 'number') {
              this.serviceConfigurableOptionForm.controls.price.setValue(response.price);
            }
            if (typeof response.setup_fee === 'number') {
              this.serviceConfigurableOptionForm.controls.setup_fee.setValue(response.setup_fee);
            }
          }, error: error => {
            if (error && error.status === 400) {
              this.notificationService.showMessage(error.error.detail);
              this.dialogRef.close(null);
            }
          }
        });
      }
    });
  }

}
