import { Component, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { IClientModel } from '@fleio-api/client-user/model/client.model';
import { UntypedFormBuilder, Validators } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { IActionResult } from '@objects-view/interfaces/actions/action-result';
import { ClientsApiService } from '@fleio-api/client-user/client/clients-api.service';
import { ActivatedRoute, Router } from '@angular/router';
import { ConfigService } from '@shared/config/config.service';
import { IClientCreateOptions } from '@fleio-api/client-user/model/client-create-options';
import { ICountry } from '@fleio-api/misc/model/country';
import { catchError, map } from 'rxjs/operators';
import { DetailsFormBase } from '@objects-view/details-form-base';
import { CustomFieldsComponent } from '@shared/fleio-data-controls/custom-fields/custom-fields.component';
import { IConfigurationModel } from '@fleio-api/configurations/model/configuration.model';
import { CallbackAction } from '@objects-view/actions/callback-action';
import { ClientGroupsApiService } from '@fleio-api/client-user/client-group/client-groups-api.service';
import { IClientGroupModel } from '@fleio-api/client-user/model/client-group.model';
import { NotificationService } from '@shared/ui-api/notification.service';
import { IIcon } from '@shared/ui/common/interfaces/icon';
import { ICustomFieldModel } from '@fleio-api/custom-fields/model/custom-field.model';
import { ValidatorsHelper } from '@shared/ui-api/helpers/validators-helper';
import { CartUtilsService } from '@fleio-api/billing/cart/cart-utils.service';
import { PhoneInputComponent } from '@shared/fleio-data-controls/phone-input/phone-input.component';
import { CookiesHelper } from '@shared/ui-api/helpers/cookies-helper';

@Component({
  selector: 'app-client-edit-form',
  templateUrl: './client-edit-form.component.html',
  styleUrls: ['./client-edit-form.component.scss']
})
export class ClientEditFormComponent extends DetailsFormBase<IClientModel> implements OnInit {
  protected readonly Object = Object;

  @ViewChildren('customFields') customFieldsList: QueryList<CustomFieldsComponent>;
  @ViewChild('phoneInput') phoneInput: PhoneInputComponent;

  clientForm = this.formBuilder.group({
    first_name: ['', Validators.required],
    last_name: ['', Validators.required],
    country: ['', Validators.required],
    company: [''],
    vat_id: [''],
    address1: ['', Validators.required],
    address2: [''],
    state: ['', Validators.required],
    city: ['', Validators.required],
    zip_code: ['', Validators.required],
    phone: ['', [Validators.required, ValidatorsHelper.internationalPhoneNumber]],
    do_not_process: [false],
  });
  clientGroups: Array<IClientGroupModel>;
  selectGroups = false;
  selectedConfiguration: IConfigurationModel;
  firstClient: boolean;

  country = this.clientForm.controls.country;
  allowCountryChange = true;

  private euCountrySelected = false;
  taxExemptAutomationOptions: Array<string>;
  hideTaxExemptAutomationDropdown = false;
  confirmViesApiDown = false;

  public createForm = true;
  public createOptions: IClientCreateOptions;
  public configurations: Array<IConfigurationModel>;
  public customFieldsByGroup: { [group: string]: { [name: string]: ICustomFieldModel } };
  public customFieldsWithoutGroup: { [name: string]: ICustomFieldModel };
  public vatIdInfo: IIcon = {
    name: 'info',
    verticalAlign: 'middle',
    fontSize: '20px',
    marginLeft: '5px',
    tooltipDirection: 'left',
    tooltip: $localize`If you have a valid KRA PIN,\nfill it in i.e AxxxxxxxxxL`
  };
  public currencyInfo: IIcon = {
    name: 'info',
    verticalAlign: 'middle',
    fontSize: '20px',
    marginLeft: '5px',
    tooltipDirection: 'left',
    tooltip: $localize`New services will use the default currency.\nExisting services are not affected by this change.`
  };
  public taxExemptAutomationInfo: IIcon = {
    name: 'info',
    verticalAlign: 'middle',
    fontSize: '20px',
    marginLeft: '5px',
    tooltipDirection: 'left',
    tooltip: $localize`VIES VAT API is used for EU customers to automatically set tax exempt state.\nTax exempt state is never changed automatically if you select Always/Never tax exempt.`
  };
  public doNotProcessInfo: IIcon = {
    name: 'info',
    verticalAlign: 'middle',
    fontSize: '20px',
    marginLeft: '5px',
    tooltipDirection: 'left',
    tooltip: $localize`If this is checked this client will not be processed by process clients periodic task.\n This effectively disables billing and automatic suspension/termination for this client.`
  };
  public taxExemptCheckboxInfo: IIcon = {
    name: 'info',
    verticalAlign: 'middle',
    fontSize: '20px',
    marginLeft: '5px',
    marginTop: '2px',
    tooltip: $localize`When client is not tax exempt,\ntaxes apply according to defined country rules.`
  };
  public autoOrderCheckboxInfo: IIcon = {
    name: 'info',
    verticalAlign: 'middle',
    fontSize: '20px',
    marginLeft: '5px',
    tooltip: $localize`When checked, an order is created automatically\nbased on Configuration > "New client automation settings"`
  };

  constructor(
    private formBuilder: UntypedFormBuilder, private clientApi: ClientsApiService, private router: Router,
    private config: ConfigService,
    private cartUtilsService: CartUtilsService,
    private clientGroupsApiService: ClientGroupsApiService,
    private notificationService: NotificationService,
    private activatedRoute: ActivatedRoute,
  ) {
    super();
  }

  findCountry(code: string): ICountry {
    return this.createOptions.countries.filter(country => country.value === code)[0];
  }

  updateAvailableConfigurations() {
    if (this.createForm && this.authSvc.feature('ui.clients&users.create.choose-config')) {
      this.configurations = [];
      if (this.createOptions) {
        for (const configuration of this.createOptions.configurations) {
          this.configurations.push(configuration);
          if (configuration.is_default) {
            this.clientForm.controls.configuration.setValue(configuration.id);
            this.selectedConfiguration = configuration;
            this.updateTaxExemptAutomationControl();
          }
        }
      }
    }
  }

  ngOnInit() {
    super.ngOnInit();
    if (this.objectController) {
      this.objectController.actionCallback = (action) => this.saveClient(action);
    }

    if (this.object?.id) {
      this.createForm = false;
    }

    if (this.authSvc.feature('ui.staff')) {
      this.clientForm.addControl('tax_exempt_automation', this.formBuilder.control('auto', Validators.required));
      this.clientForm.addControl('tax_exempt', this.formBuilder.control(false));
      this.clientForm.addControl('validate_phone_number', this.formBuilder.control(true));
      this.clientForm.addControl('currency', this.formBuilder.control('', Validators.required));
      this.clientForm.addControl('external_billing_id', this.formBuilder.control(''));
    } else {
      const queryParams = this.activatedRoute.snapshot.queryParams;
      if (this.createForm) {
        let referralCode: string;
        if (queryParams.ref) {
          referralCode = queryParams.ref;
        } else {
          referralCode = CookiesHelper.getCookie('referralCode');
        }
        if (referralCode) {
          this.clientForm.addControl('referral_code', this.formBuilder.control(referralCode));
        }
      }
      this.firstClient = this.authSvc.userData?.user && !this.authSvc.userData?.user?.clients?.length;
      if (this.primaryAction) {
        if (this.createForm) {
          if (!this.firstClient) {
            this.primaryAction.name = $localize`Create new client`;
          }
        } else {
          this.primaryAction.name = $localize`Save client`;
        }
      }
      if (this.createForm && this.firstClient) {
        this.clientForm.controls.first_name.setValue(this.authSvc.userData.user.first_name);
        this.clientForm.controls.last_name.setValue(this.authSvc.userData.user.last_name);
      }
    }

    if (this.authSvc.feature('ui.clients&users.edit.groups')) {
      this.selectGroups = true;
      this.clientForm.addControl('groups', this.formBuilder.control([]));
    }

    if (this.selectGroups) {
      this.clientGroupsApiService.list({
        page_size: 1000
      }).subscribe({
        next: response => {
          this.clientGroups = response.objects;
        }, error: () => {
          this.notificationService.showMessage($localize`Could not get client groups`);
        }
      });
    }

    if (this.objectController) {
      this.createOptions = this.objectController.additionalObjects.createOptions;
      if (this.authSvc.feature('ui.staff')) {
        this.taxExemptAutomationOptions = Object.keys(this.createOptions.tax_exempt_automation);
      }
      this.customFieldsByGroup = {};
      this.customFieldsWithoutGroup = {};
      if (this.createOptions.custom_fields) {
        for (const [name, field] of Object.entries(this.createOptions.custom_fields)) {
          field.name = name;
          if (field.group) {
            if (!this.customFieldsByGroup[field.group]) {
              this.customFieldsByGroup[field.group] = {};
            }
            this.customFieldsByGroup[field.group][field.name] = field;
          } else {
            this.customFieldsWithoutGroup[field.name] = field;
          }
        }
      }
    }

    if (this.object?.id) {
      this.clientForm.patchValue(this.object);
    }

    if (!this.createForm) {
      this.allowCountryChange = this.authSvc.feature('ui.staff') || this.authSvc.feature(
        'clients&users.clients.allow_country_change'
      );
      if (!this.allowCountryChange) {
        this.clientForm.removeControl('country');
      }
    }

    if (this.authSvc.feature('ui.staff')) {
      this.clientForm.controls.tax_exempt_automation.valueChanges.subscribe(value => {
        if (!this.hideTaxExemptAutomationDropdown) {
          this.clientForm.controls.tax_exempt.disable();
          if (value === 'always') {
            this.clientForm.controls.tax_exempt.setValue(true);
          } else if (value === 'never') {
            this.clientForm.controls.tax_exempt.setValue(false);
          } else if (value === 'auto') {
            if (!this.createForm) {
              // restore already set value
              this.clientForm.controls.tax_exempt.setValue(this.object.tax_exempt);
            }
          }
        }
      });

      this.clientForm.controls.validate_phone_number.valueChanges.subscribe(value => {
        if (!value) {
          this.clientForm.controls.phone.setValidators([Validators.required]);
          this.clientForm.controls.phone.updateValueAndValidity();
        } else {
          this.clientForm.controls.phone.setValidators([Validators.required, ValidatorsHelper.internationalPhoneNumber]);
          this.clientForm.controls.phone.updateValueAndValidity();
        }
      });

      if (this.createForm) {
        if (this.authSvc.feature('ui.clients&users.create.choose-config')) {
          this.clientForm.addControl('configuration', this.formBuilder.control(['']));
          this.updateAvailableConfigurations();
          this.clientForm.controls.configuration.valueChanges.subscribe(value => {
            this.selectedConfiguration = this.configurations.find(
              config => config.id === value
            );
            if (this.authSvc.feature('ui.clients&users.create.show-auto-order-service')) {
              // see if newly selected config has the auto_create_order setting active
              if (this.selectedConfiguration.auto_create_order) {
                // config has auto_create_order enabled, make sure related checkbox is visible & checked
                if (!this.clientForm.contains('create_auto_order_service')) {
                  this.clientForm.addControl('create_auto_order_service', this.formBuilder.control(true));
                }
              } else {
                // config has auto_create_order disabled, make sure related checkbox is hidden
                if (this.clientForm.contains('create_auto_order_service')) {
                  this.clientForm.removeControl('create_auto_order_service');
                }
              }
            }
            this.updateTaxExemptAutomationControl();
          });
        }
        if (this.authSvc.feature('ui.clients&users.create.show-auto-order-service')) {
          if (this.selectedConfiguration.auto_create_order) {
            // make sure pre-selected configuration shows auto_create_order related checkbox
            this.clientForm.addControl('create_auto_order_service', this.formBuilder.control(true));
          }
        }
      } else {
        this.selectedConfiguration = this.createOptions.configurations.find(
          config => config.id === this.object.configuration_id
        );
        this.updateTaxExemptAutomationControl();
      }
    }

    if (this.clientForm.contains('currency') && this.object && !this.object.currency) {
      this.clientForm.controls.currency.setValue(this.createOptions.default_currency);
    }

    if (this.clientForm.contains('country')) {
      if (this.object && this.object.country) {
        this.country.setValue(this.findCountry(this.object.country));
      }

      this.country.valueChanges.subscribe((selectedCountry: ICountry) => {
        if (this.phoneInput) {
          this.phoneInput.setPhoneCountry(selectedCountry?.value);
        }
        this.clientForm.controls.vat_id.setErrors(null);
        if (this.authSvc.feature('ui.staff')) {
          this.euCountrySelected = !!this.createOptions.eu_countries.find(code => code === selectedCountry.value);
          if (this.euCountrySelected) {
            if (this.hideTaxExemptAutomationDropdown) {
              this.updateTaxExemptAutomationControl();
            }
          } else {
            // non EU country, make sure tax-exempt automation field is hidden & "tax_exempt" checkbox is enabled
            if (!this.hideTaxExemptAutomationDropdown) {
              this.hideTaxExemptAutomationDropdown = true;
              if (this.createForm) {
                this.clientForm.controls.tax_exempt.setValue(false);
              } else {
                this.clientForm.controls.tax_exempt.setValue(this.object.tax_exempt);
              }
              this.clientForm.controls.tax_exempt.enable();
            }
          }
        }
      });
    }
  }

  private updateTaxExemptAutomationControl() {
    if (this.authSvc.feature('ui.staff')) {
      this.hideTaxExemptAutomationDropdown = !this.selectedConfiguration.auto_eu_tax_exemption || !this.euCountrySelected;
      if (this.createForm) {
        this.clientForm.controls.tax_exempt_automation.setValue('auto'); // set default
      }
      if (this.hideTaxExemptAutomationDropdown) {
        // make sure "tax_exempt" checkbox is enabled
        if (this.createForm) {
          this.clientForm.controls.tax_exempt.setValue(false);
        } else {
          this.clientForm.controls.tax_exempt.setValue(this.object.tax_exempt);
        }
        this.clientForm.controls.tax_exempt.enable();
      } else {
        if (!this.createForm) {
          this.clientForm.controls.tax_exempt.disable();
        }
      }
    }
  }

  getLiveFormVal() {
    // needed when having autocomplete fields that have to evaluate to a field of the selected object
    const value = this.clientForm.value;
    if (this.allowCountryChange && typeof value.country !== 'string') {
      value.country = (value.country as ICountry).value;
    }
    return value;
  }

  private warnViesApiDown(action: CallbackAction, viesError?: string) {
    // show a warning that VIES API is down
    let importantMessage = null;
    if (viesError) {
      importantMessage = viesError;
    }
    this.notificationService.confirmDialog({
      title: $localize`KRA PIN validation is not available`,
      message: $localize`VIES KRA PIN validation API server is not available. Your client will be marked as taxable.`,
      importantMessage,
      yesButtonName: $localize`Save anyway`,
      noButtonName: $localize`Cancel`,
    }).subscribe((result) => {
      if (result?.button === 'yes') {
        this.confirmViesApiDown = true;
        if (!action || action.needsResult) {
          this.objectController.loading = false;
        } else {
          this.saveClient(action);
        }
      } else {
        this.confirmViesApiDown = false;
        this.objectController.loading = false;
      }
    });
  }

  private viesServiceUnavailable(error): boolean {
    return error?.error?.vat_id && (error?.error?.vat_id === 'vies_api_down' || error?.error?.vat_id[0] === 'vies_api_down');
  }

  processError(error: any) {
    const errors = error.error;
    for (const customFields of this.customFieldsList.toArray()) {
      customFields.setBackendErrors(errors, false);
    }
    if ((typeof errors !== 'string') && ('custom_fields' in errors)) {
      delete errors.custom_fields;
    }
    this.setErrors(errors, typeof this.objectController?.dialogActionCallback === 'undefined');
  }

  saveClient(action: CallbackAction): Observable<IActionResult> {
    this.validate();
    if (this.clientForm.invalid) {
      this.displayControlErrors();
      return of({success: false, message: ''});
    }
    const value = this.clientForm.value as IClientModel;

    if (this.confirmViesApiDown) {
      value.confirm_vies_api_down = true;
    }

    if (this.authSvc.feature('ui.staff')) {
      if (this.hideTaxExemptAutomationDropdown) {
        if (!this.euCountrySelected) {
          // in case of non-EU country, default this to 'auto'
          value.tax_exempt_automation = 'auto';
        } else {
          // "tax_exempt_automation" is not used at all
          delete value.tax_exempt_automation;
        }
      }
    }

    let customFieldsToSubmit: any[] = [];
    for (const customFields of this.customFieldsList.toArray()) {

      const customFieldsValid = customFields.checkCustomFieldsForm();
      if (!customFieldsValid) {
        return of(null);
      }

      if (customFields.customFieldsToSubmit && customFields.customFieldsToSubmit.length) {
        customFieldsToSubmit = customFieldsToSubmit.concat(customFields.customFieldsToSubmit);
      }
    }
    value.custom_fields = customFieldsToSubmit;

    if (this.allowCountryChange && typeof value.country !== 'string') {
      value.country = (value.country as ICountry).value;
    }
    if (!this.allowCountryChange && !this.createForm) {
      value.country = this.object.country;
    }

    let request: Observable<IClientModel>;
    if (this.object.id) {
      value.id = this.object.id;
      request = this.clientApi.update(value.id, value);
    } else {
      request = this.clientApi.create(value);
    }

    if (!action || action.needsResult) {
      return request.pipe(
        map(() => {
          CookiesHelper.clearCookie('referralCode');
          return {success: true, message: $localize`Client saved successfully`}
        }),
        catchError((error) => {
          if (this.viesServiceUnavailable(error)) {
            this.warnViesApiDown(action, error?.error?.vies_error);
            return of({success: false, message: $localize`Failed to save client`});
          } else {
            this.processError(error);
            return of({success: false, message: $localize`Failed to save client`});
          }
        })
      );
    } else {
      this.objectController.loading = true;
      request.subscribe({
        next: () => {
          if (this.authSvc.feature('ui.staff')) {
            this.router.navigateByUrl(
              this.config.getPrevUrl('clients-users/clients')
            ).catch(() => {
            });
          } else {
            this.authSvc.checkIfLoggedIn().subscribe(() => {
              if (this.authSvc.userData.requires_email_verification) {
                this.router.navigateByUrl(
                  this.config.getPanelUrl('confirm-email')
                ).catch(() => {
                });
              } else {
                if (this.object && this.object.id) {
                  let destinationUrl = null;
                  if (this.config.authService?.userData?.user?.clients?.length) {
                    destinationUrl = `clients/${this.object.id}`;
                  }
                  this.router.navigateByUrl(
                    this.config.getPrevUrl(destinationUrl)
                  ).catch(() => {
                  });
                  if (this.object.id.toString() === this.config.activeClientId.toString()) {
                    // refresh active client if name changed
                    this.config.refreshActiveClient();
                  }
                } else {
                  let destinationUrl: string;
                  if (this.cartUtilsService.redirectToCart) {
                    destinationUrl = this.config.getPanelUrl(`billing/cart`);
                  } else {
                    destinationUrl = this.firstClient ? this.config.getPanelHomeUrl() : this.config.getPanelUrl('clients');
                  }
                  CookiesHelper.clearCookie('referralCode');
                  this.router.navigateByUrl(
                    destinationUrl
                  ).catch(() => {
                  });
                }
              }
            });
          }
        }, error: (error) => {
          if (this.viesServiceUnavailable(error)) {
            this.warnViesApiDown(action, error?.error?.vies_error);
          } else {
            this.objectController.loading = false;
            this.processError(error);
          }
        }
      });

      return of(null);
    }
  }
}
