import { Component, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, FormControl, Validators } from '@angular/forms';
import { ConfigurationsApiService } from '@fleio-api/configurations/configurations-api.service';
import { ConfigService } from '@shared/config/config.service';
import { Observable, of } from 'rxjs';
import { DetailsFormBase } from '@objects-view/details-form-base';
import { IProductModel } from '@fleio-api/billing/model/product.model';
import { IActionResult } from '@objects-view/interfaces/actions/action-result';
import { IConfigurationBillingModel } from '@fleio-api/configurations/model/configuration-billing.model';
import { NotificationService } from '@shared/ui-api/notification.service';
import { MatExpansionPanel } from '@angular/material/expansion';
import { TimeHelper } from '@shared/ui-api/helpers/time-helper';
import { ValidatorsHelper } from '@shared/ui-api/helpers/validators-helper';

@Component({
  selector: 'app-configuration-details-billing-form',
  templateUrl: './configuration-details-billing-form.component.html',
  styleUrls: ['./configuration-details-billing-form.component.scss']
})
export class ConfigurationDetailsBillingFormComponent extends DetailsFormBase<IConfigurationBillingModel> implements OnInit {
  @ViewChild('billingPanel') billingPanel: MatExpansionPanel;
  @ViewChild('agreementLimits') agreementLimits: MatExpansionPanel;
  @ViewChild('billingCycles') billingCycles: MatExpansionPanel;
  @ViewChild('general') general: MatExpansionPanel;
  @ViewChild('maxMind') maxMind: MatExpansionPanel;
  @ViewChild('clientSignupAutomation') clientSignupAutomation: MatExpansionPanel;
  @ViewChild('invoicingPanel') invoicingPanel: MatExpansionPanel;
  @ViewChild('orderPanel') orderPanel: MatExpansionPanel;
  @ViewChild('creditNotifications') creditNotifications: MatExpansionPanel;
  @ViewChild('invoiceNotifications') invoiceNotifications: MatExpansionPanel;
  @ViewChild('serviceNotifications') serviceNotifications: MatExpansionPanel;
  @ViewChild('suspension') suspension: MatExpansionPanel;
  @ViewChild('termination') termination: MatExpansionPanel;

  invoiceTaxTextVariables = $localize`{{country}}, {{tax_name}} and {{tax_percent}}`;

  configurationBillingForm = this.formBuilder.group({
    // Billing
    require_credit_card: [false, Validators.required],
    signup_charge_amount: ['', [ValidatorsHelper.requiredNumericValueValidator, Validators.min(0)]],
    signup_charge_amount_action: ['', Validators.required],
    credit_required: ['', ValidatorsHelper.requiredNumericValueValidator],
    credit_limit: ['', ValidatorsHelper.requiredNumericValueValidator],
    minim_uptodate_credit_for_invoice_payment: ['', ValidatorsHelper.requiredNumericValueValidator],
    // Limits for clients with agreement
    credit_required_with_agreement: ['', ValidatorsHelper.requiredNumericValueValidator],
    credit_limit_with_agreement: ['', ValidatorsHelper.requiredNumericValueValidator],
    // Billing cycles
    billing_cycle_as_calendar_month: [''],
    auto_settle_invoiced_periods_external_billing: [''],
    // General
    company_info: ['', Validators.required],
    sender_name: [''],
    sender_email: [''],
    use_custom_logo_for_pdf_invoices: [false],
    pdf_logo_file_name: [null],
    // MaxMind fraud check
    fraud_check: [''],
    enable_maxmind_insights: [''],
    maxmind_fraud_score: [''],
    skip_fraud_check_for_active_clients: [''],
    automatically_mark_new_orders_as_fraud_for_clients_with_fraud_order: [''],

    // Client signup automation
    auto_create_order: [false],
    auto_order_service: [null],
    auto_order_service_cycle: [null],
    auto_order_service_params: [''],
    client_initial_credit: [0],
    // Invoicing
    generate_invoices: [''],
    generate_invoices_after: [false],
    generate_invoices_after_dt: [''],
    generate_invoices_after_time: [''],
    do_not_invoice_services_with_zero_price: [''],
    allow_multiple_add_credit_invoices: [false],
    send_notifications_for_unpaid_invoices: [''],
    create_todo_on_invoice_payment: [''],
    auto_settle_usage: [''],
    invoicing_option: [''],
    detailed_invoices: [''],
    next_paid_invoice_number: ['', [Validators.required, ValidatorsHelper.requiredIntegerValidator]],
    next_paid_invoice_number_format: ['', Validators.required],
    limit_billable_seconds_per_month: [''],
    billable_seconds_per_month: ['', ValidatorsHelper.requiredNumericValueValidator],
    issue_invoice_before_next_due_date: [''],
    next_invoice_date_offset: ['', [Validators.required, ValidatorsHelper.requiredIntegerValidator]],
    auto_eu_tax_exemption: [''],
    provider_home_country: [''],
    default_invoice_tax_text: [''],
    zero_tax_eu_invoice_text: [''],
    add_tax_for_credit_invoices: [''],
    // Credit notifications
    credit_notifications_enabled: [''],
    credit_notifications_when_agreement_enabled: [''],
    first_credit_remaining_hours: ['', ValidatorsHelper.requiredIntegerValidator],
    first_credit_notification_template: [''],
    second_credit_remaining_hours: ['', ValidatorsHelper.requiredIntegerValidator],
    second_credit_notification_template: [''],
    third_credit_remaining_hours: ['', ValidatorsHelper.requiredIntegerValidator],
    third_credit_notification_template: [''],
    // Invoice notifications
    invoice_notifications_enabled: [false],
    first_invoice_payment_reminder_remaining_hours: [168, ValidatorsHelper.requiredIntegerValidator],
    first_invoice_payment_reminder_notification_template: [''],
    second_invoice_payment_reminder_remaining_hours: [48, ValidatorsHelper.requiredIntegerValidator],
    second_invoice_payment_reminder_notification_template: [''],
    first_invoice_payment_overdue_hours: [24, ValidatorsHelper.requiredIntegerValidator],
    first_invoice_payment_overdue_notification_template: [''],
    second_invoice_payment_overdue_hours: [72, ValidatorsHelper.requiredIntegerValidator],
    second_invoice_payment_overdue_notification_template: [''],
    third_invoice_payment_overdue_hours: [128, ValidatorsHelper.requiredIntegerValidator],
    third_invoice_payment_overdue_notification_template: [''],
    invoice_payment_confirmation_notification_template: [''],
    invoice_refund_confirmation_notification_template: [''],
    // Service notifications
    service_notifications_enabled: [false],
    service_suspended_notification_template: [''],
    service_resumed_notification_template: [''],

    // Order settings
    order_grace_days: [''],

    // Upgrade/downgrade settings
    enduser_allow_service_cycle_change: [false],
    enduser_shorten_current_product_service_cycle: [false],
    enduser_shorten_new_product_service_cycle: [false],

    // Suspension
    auto_suspend: [''],
    auto_suspend_delay_hours_enabled: [''],
    auto_suspend_delay_hours: ['', ValidatorsHelper.requiredIntegerValidator],
    auto_suspend_delay_credit_enabled: [''],
    auto_suspend_delay_credit: ['', ValidatorsHelper.requiredNumericValueValidator],
    auto_suspend_notification_template: [''],
    auto_unsuspend_client_on_credit_update: [''],
    // Termination
    auto_terminate: [''],
    suspend_instead_of_terminate: [''],
    auto_terminate_delay_hours: ['', ValidatorsHelper.requiredIntegerValidator],
    auto_terminate_notification_template: ['', Validators.required],
  });

  autoOrderProduct: IProductModel;
  billingConfiguration: IConfigurationBillingModel;
  updatingControls = false;
  customPdfLogo = this.configurationBillingForm.controls.use_custom_logo_for_pdf_invoices;
  private pdfLogo: File;
  timeHelper: TimeHelper;

  constructor(
    private formBuilder: UntypedFormBuilder, private configurationsApiService: ConfigurationsApiService,
    private config: ConfigService, private notificationService: NotificationService
  ) {
    super();
    this.timeHelper = new TimeHelper(config);
  }

  ngOnInit() {
    super.ngOnInit();
    this.initTabData(); // init tab data in case page has no multiple tabs to ensure actionCallback is set
    if (this.objectController) {
      this.billingConfiguration =
        this.objectController.additionalObjects.billingConfiguration as IConfigurationBillingModel;
    }
    this.configurationBillingForm.valueChanges.subscribe(() => {
      if (!this.updatingControls) {
        this.updatingControls = true;
        this.updateBillingControls();
        this.updateUpgradeDowngradeControls();
        this.updateMaxMindControls();
        this.updateClientSignupAutomationControls();
        this.updateInvoicingControls();
        this.updateCreditNotificationsControls();
        this.updateInvoiceNotificationsControls();
        this.updateServiceNotificationsControls();
        this.updateSuspensionControls();
        this.updateTerminationControls();
        this.updatingControls = false;
      }
    });

    if (this.billingConfiguration) {
      this.configurationBillingForm.patchValue(this.billingConfiguration);
      this.patchDateTimeFields();
    } else {
      this.configurationBillingForm.disable();
    }
  }

  private patchDateTimeFields() {
    // patch generate invoices after setting
    if (this.billingConfiguration.generate_invoices_after_dt) {
      this.configurationBillingForm.controls.generate_invoices_after_dt.setValue(
        new Date(this.billingConfiguration.generate_invoices_after_dt)
      );
      this.configurationBillingForm.controls.generate_invoices_after_time.setValue(
        new Date(this.billingConfiguration.generate_invoices_after_dt).toLocaleTimeString(this.config.locale)
      );
    }
  }

  protected initTabData() {
    if (this.objectController) {
      this.objectController.actionCallback = () => this.saveConfiguration();
    }
  }

  updateMaxMindControls() {
    const maxMindControls = this.configurationBillingForm.controls;
    if (maxMindControls.fraud_check.value) {
      maxMindControls.enable_maxmind_insights.enable();
      maxMindControls.maxmind_fraud_score.enable();
      maxMindControls.skip_fraud_check_for_active_clients.enable();
      maxMindControls.automatically_mark_new_orders_as_fraud_for_clients_with_fraud_order.enable();
    } else {
      maxMindControls.enable_maxmind_insights.disable();
      maxMindControls.maxmind_fraud_score.disable();
      maxMindControls.skip_fraud_check_for_active_clients.disable();
      maxMindControls.automatically_mark_new_orders_as_fraud_for_clients_with_fraud_order.disable();
    }
  }

  updateBillingControls() {
    const billingControls = this.configurationBillingForm.controls;
    if (billingControls.require_credit_card.value) {
      billingControls.signup_charge_amount.enable();
      billingControls.signup_charge_amount_action.enable();
    } else {
      billingControls.signup_charge_amount.disable();
      billingControls.signup_charge_amount_action.disable();
    }
  }

  updateUpgradeDowngradeControls() {
    const billingControls = this.configurationBillingForm.controls;
    if (billingControls.enduser_allow_service_cycle_change.value) {
      billingControls.enduser_shorten_current_product_service_cycle.enable();
      billingControls.enduser_shorten_new_product_service_cycle.enable();
    } else {
      billingControls.enduser_shorten_current_product_service_cycle.disable();
      billingControls.enduser_shorten_new_product_service_cycle.disable();
    }
  }

  updateClientSignupAutomationControls() {
    const clientSignupAutomationControls = this.configurationBillingForm.controls;
    if (clientSignupAutomationControls.auto_create_order.value) {
      if (clientSignupAutomationControls.auto_order_service.value === -1) {
        clientSignupAutomationControls.auto_order_service.setValue(null);
      }
      if (clientSignupAutomationControls.auto_order_service_cycle.value === -1) {
        clientSignupAutomationControls.auto_order_service_cycle.setValue(null);
      }
      clientSignupAutomationControls.auto_order_service.enable();
      clientSignupAutomationControls.auto_order_service.setValidators(Validators.required);
      clientSignupAutomationControls.auto_order_service.updateValueAndValidity();
      clientSignupAutomationControls.auto_order_service_cycle.enable();
      clientSignupAutomationControls.auto_order_service_cycle.setValidators(Validators.required);
      clientSignupAutomationControls.auto_order_service_cycle.updateValueAndValidity();
      clientSignupAutomationControls.auto_order_service_params.enable();

      for (const product of this.billingConfiguration.products) {
        if (product.id === clientSignupAutomationControls.auto_order_service.value) {
          this.autoOrderProduct = product;
        }
      }
    } else {
      clientSignupAutomationControls.auto_order_service.disable();
      clientSignupAutomationControls.auto_order_service.clearValidators();
      clientSignupAutomationControls.auto_order_service_cycle.disable();
      clientSignupAutomationControls.auto_order_service_cycle.clearValidators();
      clientSignupAutomationControls.auto_order_service_params.disable();
    }
  }

  updateInvoicingControls() {
    const invoicingControls = this.configurationBillingForm.controls;
    if (invoicingControls.generate_invoices.value) {
      invoicingControls.generate_invoices_after.enable();
      invoicingControls.generate_invoices_after_dt.enable();
      invoicingControls.generate_invoices_after_time.enable();
      invoicingControls.do_not_invoice_services_with_zero_price.enable();
      invoicingControls.send_notifications_for_unpaid_invoices.enable();
      invoicingControls.create_todo_on_invoice_payment.enable();

      invoicingControls.invoicing_option.enable();
      invoicingControls.detailed_invoices.enable();
      invoicingControls.next_paid_invoice_number.enable();
      invoicingControls.next_paid_invoice_number_format.enable();
      invoicingControls.issue_invoice_before_next_due_date.enable();

      if (invoicingControls.issue_invoice_before_next_due_date.value) {
        invoicingControls.next_invoice_date_offset.enable();
      } else {
        invoicingControls.next_invoice_date_offset.disable();
      }

    } else {
      invoicingControls.generate_invoices_after.disable();
      invoicingControls.generate_invoices_after_dt.disable();
      invoicingControls.generate_invoices_after_time.enable();
      invoicingControls.do_not_invoice_services_with_zero_price.disable();
      invoicingControls.send_notifications_for_unpaid_invoices.disable();
      invoicingControls.create_todo_on_invoice_payment.disable();

      invoicingControls.invoicing_option.disable();
      invoicingControls.detailed_invoices.disable();
      invoicingControls.next_paid_invoice_number.disable();
      invoicingControls.next_paid_invoice_number_format.disable();
      invoicingControls.issue_invoice_before_next_due_date.disable();

      invoicingControls.next_invoice_date_offset.disable();
    }

    if (invoicingControls.limit_billable_seconds_per_month.value) {
      invoicingControls.billable_seconds_per_month.enable();
    } else {
      invoicingControls.billable_seconds_per_month.disable();
    }

    if (invoicingControls.auto_eu_tax_exemption.value) {
      invoicingControls.provider_home_country.enable();
    } else {
      invoicingControls.provider_home_country.disable();
    }

    if (invoicingControls.generate_invoices_after.value) {
      invoicingControls.generate_invoices_after_dt.enable();
      invoicingControls.generate_invoices_after_dt.setValidators(Validators.required);
      invoicingControls.generate_invoices_after_dt.updateValueAndValidity();
      invoicingControls.generate_invoices_after_time.enable();
      invoicingControls.generate_invoices_after_time.setValidators(Validators.required);
      invoicingControls.generate_invoices_after_time.updateValueAndValidity();
    } else {
      invoicingControls.generate_invoices_after_dt.disable();
      invoicingControls.generate_invoices_after_dt.clearValidators();
      invoicingControls.generate_invoices_after_time.disable();
      invoicingControls.generate_invoices_after_time.clearValidators();
    }
  }

  updateCreditNotificationsControls() {
    const creditNotificationsControls = this.configurationBillingForm.controls;
    if (creditNotificationsControls.credit_notifications_enabled.value) {
      creditNotificationsControls.credit_notifications_when_agreement_enabled.enable();
      creditNotificationsControls.first_credit_remaining_hours.enable();
      creditNotificationsControls.first_credit_notification_template.enable();
      creditNotificationsControls.second_credit_remaining_hours.enable();
      creditNotificationsControls.second_credit_notification_template.enable();
      creditNotificationsControls.third_credit_remaining_hours.enable();
      creditNotificationsControls.third_credit_notification_template.enable();
    } else {
      creditNotificationsControls.credit_notifications_when_agreement_enabled.disable();
      creditNotificationsControls.first_credit_remaining_hours.disable();
      creditNotificationsControls.first_credit_notification_template.disable();
      creditNotificationsControls.second_credit_remaining_hours.disable();
      creditNotificationsControls.second_credit_notification_template.disable();
      creditNotificationsControls.third_credit_remaining_hours.disable();
      creditNotificationsControls.third_credit_notification_template.disable();
    }
  }

  updateInvoiceNotificationsControls() {
    const invoiceNotificationsControls = this.configurationBillingForm.controls;
    if (invoiceNotificationsControls.invoice_notifications_enabled.value) {
      invoiceNotificationsControls.first_invoice_payment_reminder_remaining_hours.enable();
      invoiceNotificationsControls.first_invoice_payment_reminder_notification_template.enable();
      invoiceNotificationsControls.second_invoice_payment_reminder_remaining_hours.enable();
      invoiceNotificationsControls.second_invoice_payment_reminder_notification_template.enable();
      invoiceNotificationsControls.first_invoice_payment_overdue_hours.enable();
      invoiceNotificationsControls.first_invoice_payment_overdue_notification_template.enable();
      invoiceNotificationsControls.second_invoice_payment_overdue_hours.enable();
      invoiceNotificationsControls.second_invoice_payment_overdue_notification_template.enable();
      invoiceNotificationsControls.third_invoice_payment_overdue_hours.enable();
      invoiceNotificationsControls.third_invoice_payment_overdue_notification_template.enable();
      invoiceNotificationsControls.invoice_payment_confirmation_notification_template.enable();
      invoiceNotificationsControls.invoice_refund_confirmation_notification_template.enable();
    } else {
      invoiceNotificationsControls.first_invoice_payment_reminder_remaining_hours.disable();
      invoiceNotificationsControls.first_invoice_payment_reminder_notification_template.disable();
      invoiceNotificationsControls.second_invoice_payment_reminder_remaining_hours.disable();
      invoiceNotificationsControls.second_invoice_payment_reminder_notification_template.disable();
      invoiceNotificationsControls.first_invoice_payment_overdue_hours.disable();
      invoiceNotificationsControls.first_invoice_payment_overdue_notification_template.disable();
      invoiceNotificationsControls.second_invoice_payment_overdue_hours.disable();
      invoiceNotificationsControls.second_invoice_payment_overdue_notification_template.disable();
      invoiceNotificationsControls.third_invoice_payment_overdue_hours.disable();
      invoiceNotificationsControls.third_invoice_payment_overdue_notification_template.disable();
      invoiceNotificationsControls.invoice_payment_confirmation_notification_template.disable();
      invoiceNotificationsControls.invoice_refund_confirmation_notification_template.disable();
    }
  }

  updateServiceNotificationsControls() {
    const serviceNotificationsControls = this.configurationBillingForm.controls;
    if (serviceNotificationsControls.service_notifications_enabled.value) {
      serviceNotificationsControls.service_suspended_notification_template.enable();
      serviceNotificationsControls.service_resumed_notification_template.enable();
    } else {
      serviceNotificationsControls.service_suspended_notification_template.disable();
      serviceNotificationsControls.service_resumed_notification_template.disable();
    }
  }

  updateSuspensionControls() {
    const suspensionControls = this.configurationBillingForm.controls;
    if (suspensionControls.auto_suspend.value) {
      suspensionControls.auto_suspend_delay_hours_enabled.enable();
      if (suspensionControls.auto_suspend_delay_hours_enabled.value) {
        suspensionControls.auto_suspend_delay_hours.enable();
      } else {
        suspensionControls.auto_suspend_delay_hours.disable();
      }

      suspensionControls.auto_suspend_delay_credit_enabled.enable();

      if (suspensionControls.auto_suspend_delay_credit_enabled.value) {
        suspensionControls.auto_suspend_delay_credit.enable();
      } else {
        suspensionControls.auto_suspend_delay_credit.disable();
      }

      suspensionControls.auto_suspend_notification_template.enable();
    } else {
      suspensionControls.auto_suspend_delay_hours_enabled.disable();
      suspensionControls.auto_suspend_delay_hours.disable();
      suspensionControls.auto_suspend_delay_credit_enabled.disable();
      suspensionControls.auto_suspend_delay_credit.disable();
      suspensionControls.auto_suspend_notification_template.disable();
    }
  }

  updateTerminationControls() {
    const terminationControls = this.configurationBillingForm.controls;
    if (terminationControls.auto_terminate.value) {
      terminationControls.auto_terminate_delay_hours.enable();
      terminationControls.auto_terminate_notification_template.enable();
    } else {
      terminationControls.auto_terminate_delay_hours.disable();
      terminationControls.auto_terminate_notification_template.disable();
    }
  }

  private openErroredControlPanel() {
    Object.keys(this.formGroup.controls).map(name => {
      const control = this.formGroup.controls[name] as FormControl;
      if (control.invalid) {
        let element;
        const input = document.querySelector(`input[formControlName='${name}']`);
        if (input) {
          element = input;
        } else {
          element = document.querySelector(`mat-select[formControlName='${name}']`);
        }
        const closestPanel = element.closest('mat-expansion-panel');
        if (closestPanel && closestPanel.id && this.hasOwnProperty(closestPanel.id)) {
          this[closestPanel.id].open();
        }
      }
    });
  }

  saveConfiguration(): Observable<IActionResult> {
    const value = this.configurationBillingForm.getRawValue();
    this.validate();
    if (this.formGroup.invalid) {
      this.displayControlErrors();
      this.openErroredControlPanel();
      return of(null);
    }

    if (value.generate_invoices_after && value.generate_invoices_after_dt) {
      const error = this.timeHelper.processDateFieldTime(
        value.generate_invoices_after_dt,
        this.configurationBillingForm.controls.generate_invoices_after_time
      ).error;
      if (error) {
        this.displayControlErrors(); // will see the errored time controls & scrolls to top
        this.openErroredControlPanel();
        return of(null);
      }
    }

    value.id = this.object.id;

    const jsonValue = JSON.stringify(value);

    const formData = new FormData();
    formData.append('data', jsonValue);

    if (this.pdfLogo) {
      formData.append('pdf_logo_file', this.pdfLogo, this.pdfLogo.name);
    }
    const request = this.configurationsApiService.objectPutAction(value.id, 'billing', formData);

    this.objectController.loading = true;
    request.subscribe((response) => {
      this.notificationService.showMessage(response.detail);
    }, (error) => {
      this.setErrors(error.error);
    }).add(() => {
      this.objectController.loading = false;
    });

    return of(null);
  }

  pdfLogoChanged($event: Event) {
    const files = ($event.target as HTMLInputElement).files;
    this.pdfLogo = files.length > 0 ? files[0] : null;

    const URL = window.URL || window.webkitURL;
    const img = new Image();
    const objectUrl = URL.createObjectURL(this.pdfLogo);
    const imageMaxDimensions = 550;
    img.onload = () => {
      if (img.width > imageMaxDimensions || img.height > imageMaxDimensions) {
        this.configurationBillingForm.controls.pdf_logo_file_name.setErrors({
          custom: true,
          message: $localize`Image is larger than ${imageMaxDimensions} x ${imageMaxDimensions} px. Choose a smaller image.`,
        });
      }
      URL.revokeObjectURL(objectUrl);
    };
    img.src = objectUrl;

    const fileName = this.pdfLogo ? this.pdfLogo.name : null;
    this.configurationBillingForm.controls.pdf_logo_file_name.setValue(fileName);
  }
}
