import { Component, OnInit } from '@angular/core';
import { DetailsFormBase } from '@objects-view/details-form-base';
import { UntypedFormBuilder, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { ConfigService } from '@shared/config/config.service';
import { IServiceModel } from '@fleio-api/billing/model/service.model';
import { IServiceUpgradeOptionsModel } from '@fleio-api/billing/model/service-upgrade-options.model';
import { IServiceUpgradeModel } from '@fleio-api/billing/model/service-upgrade-.model';
import { ServicesApiService } from '@fleio-api/billing/services/service-api.service';
import { IProductCycleModel } from '@fleio-api/billing/model/product-cycle.model';
import { NotificationService } from '@shared/ui-api/notification.service';

@Component({
  selector: 'app-service-change-form',
  templateUrl: './service-change-form.component.html',
  styleUrls: ['./service-change-form.component.scss']
})
export class ServiceChangeFormComponent extends DetailsFormBase<IServiceModel> implements OnInit {
  changeOptionsForm = this.formBuilder.group({
    newServiceCycle: ['', Validators.required],
    newServiceProduct: [''],
  });

  upgradeOptions: IServiceUpgradeOptionsModel;
  upgradeInProgress: boolean;
  confirmChanges: boolean;
  optionsChanged: boolean = false;
  upgrade: IServiceUpgradeModel;
  initialConfigOptionValues;
  configOptionValues: { [key: number]: string } = {};
  selectedProduct;
  agreedToRefundAdvancePayments = false;

  constructor(
    private formBuilder: UntypedFormBuilder,
    private router: Router,
    private servicesApi: ServicesApiService,
    public config: ConfigService,
    private notificationService: NotificationService,
  ) {
    super();
  }

  newlyAddedOption(newConfigOpt) {
    return !this.upgradeOptions.configurable_options.find(o => o.option === newConfigOpt.option)
  }

  checkIfOptionsChanged() {
    this.optionsChanged = this.changeOptionsForm.controls.newServiceCycle.value !== this.upgradeOptions.cycle.id;
    if (!this.optionsChanged && this.initialConfigOptionValues) {
      this.optionsChanged = this.initialConfigOptionValues !== JSON.stringify(this.configOptionValues);
    }
  }

  displayCycle(cycle: IProductCycleModel, productChanged = false) {
    if (this.authSvc.feature('ui.enduser')) {
      if (productChanged) {
        if (this.upgradeOptions && !this.upgradeOptions.enduser_shorten_new_product_service_cycle) {
          return cycle.period_in_days >= this.upgradeOptions.cycle.period_in_days;
        }
      } else {
        if (this.upgradeOptions && !this.upgradeOptions.enduser_shorten_current_product_service_cycle) {
          return cycle.period_in_days >= this.upgradeOptions.cycle.period_in_days;
        }
      }
    }
    return true;
  }

  ngOnInit() {
    if (!this.objectController) {
      return;
    }
    this.upgradeOptions = this.objectController.additionalObjects.upgradeOptions as IServiceUpgradeOptionsModel;
    if (this.upgradeOptions && !this.upgradeOptions.enduser_allow_service_cycle_change &&
      this.authSvc.feature('ui.enduser')) {
      this.changeOptionsForm.controls.newServiceCycle.disable();
    }
    this.upgradeInProgress = !!this.upgradeOptions.existing_upgrade_invoice;
    if (!this.upgradeInProgress) {
      this.changeOptionsForm.patchValue({
        newServiceCycle: this.upgradeOptions.cycle.id,
      });
      this.changeOptionsForm.patchValue({
        newServiceProduct: this.upgradeOptions.product.id,
      });

      this.setConfigOptionsUpgrades(this.upgradeOptions.configurable_options_upgrades);

      for (const option of this.upgradeOptions.configurable_options) {
        this.configOptionValues[option.option] = option.option_value;
      }

      this.initialConfigOptionValues = JSON.stringify(this.configOptionValues);

      this.changeOptionsForm.controls.newServiceCycle.valueChanges.subscribe(newValue => {
        this.checkIfOptionsChanged();
        this.servicesApi.upgradeOptions(
          this.object.id, newValue, this.selectedProduct?.id
        ).subscribe(newUpgradeOptions => {
          this.setConfigOptionsUpgrades(newUpgradeOptions.configurable_options_upgrades);
          this.setSimilarOptions();
        });
      });

      this.changeOptionsForm.controls.newServiceProduct.valueChanges.subscribe(productId => {
        this.selectedProduct = this.upgradeOptions.upgrades.find(p => p.id === productId);
        if (this.selectedProduct) {
          // selectedProduct is populated, upgrade will result in changing the current product
          this.setConfigOptionsUpgrades(this.selectedProduct.configurable_options);
          this.setSimilarCycle();
        } else {
          // product not found in upgrades list, it means user has chosen current product again, come to initial opts
          this.servicesApi.upgradeOptions(
            this.object.id,
          ).subscribe(newUpgradeOptions => {
            this.setConfigOptionsUpgrades(newUpgradeOptions.configurable_options_upgrades);
            this.setSimilarOptions();
            this.changeOptionsForm.controls.newServiceCycle.setValue(this.upgradeOptions.cycle.id);
          });
        }
      });
    }
  }

  setSimilarOptions() {
    for (const configOption of this.upgradeOptions.configurable_options) {
      for (const otherCycleConfigOption of this.upgradeOptions.configurable_options_upgrades) {
        if (configOption.option === otherCycleConfigOption.id) {
          this.configOptionValues[otherCycleConfigOption.id] = configOption.option_value;
        }
      }
    }
  }

  setSimilarCycle() {
    for (const cycle of this.selectedProduct.cycles) {
      if (cycle.display_name === this.upgradeOptions.cycle.display_name) {
        this.changeOptionsForm.controls.newServiceCycle.setValue(cycle.id);
        break;
      }
    }
  }

  setConfigOptionsUpgrades(confOpts) {
    this.upgradeOptions.configurable_options_upgrades = JSON.parse(JSON.stringify(confOpts));
    this.configOptionValues = {};
    for (const option of confOpts) {
      this.configOptionValues[option.id] = null;
    }
  }

  checkUpgrade() {
    this.validate();
    const configOptions = [];
    for (const option of this.upgradeOptions.configurable_options_upgrades) {
      if (this.configOptionValues.hasOwnProperty(option.id)) {
        if (this.configOptionValues[option.id] !== null) {
          configOptions.push({option: option.id, option_value: this.configOptionValues[option.id]});
        }
      }
    }

    this.upgrade = {
      configurable_options: configOptions,
      cycle: this.changeOptionsForm.controls.newServiceCycle.value,
      product: this.changeOptionsForm.controls.newServiceProduct.value,
    };
    this.servicesApi.upgrade(this.object.id, this.upgrade).subscribe({
      next: upgrade => {
        if (upgrade.is_downgrade && !upgrade.credit_on_downgrade) {
          upgrade.product_upgrade_price = 0;
          upgrade.total_due = 0;
        }
        this.upgrade = upgrade;
        this.confirmChanges = true;
      }, error: error => {
        if (error.error) {
          if (Array.isArray(error.error.configurable_options) && error.error.configurable_options.length) {
            // treat configurable options errors coming as a list separately
            this.backendErrors = {};
            for (const respError of error.error.configurable_options) {
              Object.assign(this.backendErrors, respError);
            }
            return;
          } else {
            if (this.formErrors.setBackendErrors(error.error, this.configOptionValues)) {
              this.backendErrors = error.error;
              return;
            }
          }
        }
      }
    });
  }

  placeOrder() {
    this.validate();
    this.upgrade.confirm = true;
    this.upgrade.cycle = this.changeOptionsForm.controls.newServiceCycle.value;
    this.upgrade.product = this.changeOptionsForm.controls.newServiceProduct.value;
    this.objectController.loading = true;
    this.servicesApi.upgrade(this.object.id, this.upgrade).subscribe(response => {
      if (response?.invoice) {
        this.router.navigateByUrl(
          this.config.getPanelUrl(`billing/invoices/${response.invoice}`)
        ).catch(() => {
        });
      } else {
        this.router.navigateByUrl(
          this.config.getPanelUrl(`billing/services/${this.object.id}`)
        ).catch(() => {
        });
        this.notificationService.showMessage(response.detail);
      }
    }, (error) => {
      this.objectController.loading = false;
      this.formErrors.showError(error.error.detail);
    });
  }
}
