import {
  Component,
  EventEmitter,
  Input,
  OnDestroy,
  OnInit,
  Output,
  ViewChild,
} from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { Router } from "@angular/router";
import { Subject, takeUntil } from "rxjs";

import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { OrganizationCreateRequest } from "@bitwarden/common/admin-console/models/request/organization-create.request";
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
import { OrganizationUpgradeRequest } from "@bitwarden/common/admin-console/models/request/organization-upgrade.request";
import { ProviderOrganizationCreateRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-organization-create.request";
import { ProviderResponse } from "@bitwarden/common/admin-console/models/response/provider/provider.response";
import { PaymentMethodType, PlanType } from "@bitwarden/common/billing/enums";
import { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request";
import { BillingResponse } from "@bitwarden/common/billing/models/response/billing.response";
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
import { ProductType } from "@bitwarden/common/enums";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { OrgKey } from "@bitwarden/common/types/key";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";

import { OrganizationCreateModule } from "../../admin-console/organizations/create/organization-create.module";
import { BillingSharedModule, secretsManagerSubscribeFormFactory } from "../shared";
import { PaymentComponent } from "../shared/payment.component";
import { TaxInfoComponent } from "../shared/tax-info.component";

interface OnSuccessArgs {
  organizationId: string;
}

const Allowed2020PlansForLegacyProviders = [
  PlanType.TeamsMonthly2020,
  PlanType.TeamsAnnually2020,
  PlanType.EnterpriseAnnually2020,
  PlanType.EnterpriseMonthly2020,
];

@Component({
  selector: "app-organization-plans",
  templateUrl: "organization-plans.component.html",
  standalone: true,
  imports: [BillingSharedModule, OrganizationCreateModule],
})
export class OrganizationPlansComponent implements OnInit, OnDestroy {
  @ViewChild(PaymentComponent) paymentComponent: PaymentComponent;
  @ViewChild(TaxInfoComponent) taxComponent: TaxInfoComponent;

  @Input() organizationId: string;
  @Input() showFree = true;
  @Input() showCancel = false;
  @Input() acceptingSponsorship = false;
  @Input() currentPlan: PlanResponse;

  @Input()
  get product(): ProductType {
    return this._product;
  }

  set product(product: ProductType) {
    this._product = product;
    this.formGroup?.controls?.product?.setValue(product);
  }

  private _product = ProductType.Free;

  @Input()
  get plan(): PlanType {
    return this._plan;
  }

  set plan(plan: PlanType) {
    this._plan = plan;
    this.formGroup?.controls?.plan?.setValue(plan);
  }

  private _plan = PlanType.Free;
  @Input() providerId?: string;
  @Output() onSuccess = new EventEmitter<OnSuccessArgs>();
  @Output() onCanceled = new EventEmitter<void>();
  @Output() onTrialBillingSuccess = new EventEmitter();

  loading = true;
  selfHosted = false;
  productTypes = ProductType;
  formPromise: Promise<string>;
  singleOrgPolicyAppliesToActiveUser = false;
  isInTrialFlow = false;
  discount = 0;

  secretsManagerSubscription = secretsManagerSubscribeFormFactory(this.formBuilder);

  formGroup = this.formBuilder.group({
    name: [""],
    billingEmail: ["", [Validators.email]],
    businessOwned: [false],
    premiumAccessAddon: [false],
    additionalStorage: [0, [Validators.min(0), Validators.max(99)]],
    additionalSeats: [0, [Validators.min(0), Validators.max(100000)]],
    clientOwnerEmail: ["", [Validators.email]],
    plan: [this.plan],
    product: [this.product],
    secretsManager: this.secretsManagerSubscription,
  });

  passwordManagerPlans: PlanResponse[];
  secretsManagerPlans: PlanResponse[];
  organization: Organization;
  sub: OrganizationSubscriptionResponse;
  billing: BillingResponse;
  provider: ProviderResponse;

  private destroy$ = new Subject<void>();

  constructor(
    private apiService: ApiService,
    private i18nService: I18nService,
    private platformUtilsService: PlatformUtilsService,
    private cryptoService: CryptoService,
    private router: Router,
    private syncService: SyncService,
    private policyService: PolicyService,
    private organizationService: OrganizationService,
    private logService: LogService,
    private messagingService: MessagingService,
    private formBuilder: FormBuilder,
    private organizationApiService: OrganizationApiServiceAbstraction,
    private providerApiService: ProviderApiServiceAbstraction,
  ) {
    this.selfHosted = platformUtilsService.isSelfHost();
  }

  async ngOnInit() {
    if (this.organizationId) {
      this.organization = await this.organizationService.get(this.organizationId);
      this.billing = await this.organizationApiService.getBilling(this.organizationId);
      this.sub = await this.organizationApiService.getSubscription(this.organizationId);
    }

    if (!this.selfHosted) {
      const plans = await this.apiService.getPlans();
      this.passwordManagerPlans = plans.data.filter((plan) => !!plan.PasswordManager);
      this.secretsManagerPlans = plans.data.filter((plan) => !!plan.SecretsManager);

      if (this.product === ProductType.Enterprise || this.product === ProductType.Teams) {
        this.formGroup.controls.businessOwned.setValue(true);
      }
    }

    if (this.currentPlan && this.currentPlan.product !== ProductType.Enterprise) {
      const upgradedPlan = this.passwordManagerPlans.find((plan) =>
        this.currentPlan.product === ProductType.Free
          ? plan.type === PlanType.FamiliesAnnually
          : plan.upgradeSortOrder == this.currentPlan.upgradeSortOrder + 1,
      );

      this.plan = upgradedPlan.type;
      this.product = upgradedPlan.product;
    }

    if (this.hasProvider) {
      this.formGroup.controls.businessOwned.setValue(true);
      this.changedOwnedBusiness();
      this.provider = await this.providerApiService.getProvider(this.providerId);
      const providerDefaultPlan = this.passwordManagerPlans.find(
        (plan) => plan.type === PlanType.TeamsAnnually,
      );
      this.plan = providerDefaultPlan.type;
      this.product = providerDefaultPlan.product;
    }

    if (!this.createOrganization) {
      this.upgradeFlowPrefillForm();
    } else {
      this.formGroup.controls.name.addValidators([Validators.required, Validators.maxLength(50)]);
      this.formGroup.controls.billingEmail.addValidators(Validators.required);
    }

    this.policyService
      .policyAppliesToActiveUser$(PolicyType.SingleOrg)
      .pipe(takeUntil(this.destroy$))
      .subscribe((policyAppliesToActiveUser) => {
        this.singleOrgPolicyAppliesToActiveUser = policyAppliesToActiveUser;
      });

    if (!this.selfHosted) {
      this.changedProduct();
    }

    this.loading = false;
  }

  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }

  get singleOrgPolicyBlock() {
    return this.singleOrgPolicyAppliesToActiveUser && !this.hasProvider;
  }

  get createOrganization() {
    return this.organizationId == null;
  }

  get upgradeRequiresPaymentMethod() {
    return (
      this.organization?.planProductType === ProductType.Free &&
      !this.showFree &&
      !this.billing?.paymentSource
    );
  }

  get selectedPlan() {
    return this.passwordManagerPlans.find(
      (plan) => plan.type === this.formGroup.controls.plan.value,
    );
  }

  get selectedSecretsManagerPlan() {
    return this.secretsManagerPlans.find(
      (plan) => plan.type === this.formGroup.controls.plan.value,
    );
  }

  get selectedPlanInterval() {
    return this.selectedPlan.isAnnual ? "year" : "month";
  }

  isProviderQualifiedFor2020Plan() {
    const targetDate = new Date("2023-11-06");

    if (!this.provider || !this.provider.creationDate) {
      return false;
    }

    const creationDate = new Date(this.provider.creationDate);
    return creationDate < targetDate;
  }

  get selectableProducts() {
    if (this.acceptingSponsorship) {
      const familyPlan = this.passwordManagerPlans.find(
        (plan) => plan.type === PlanType.FamiliesAnnually,
      );
      this.discount = familyPlan.PasswordManager.basePrice;
      return [familyPlan];
    }

    const businessOwnedIsChecked = this.formGroup.controls.businessOwned.value;

    const result = this.passwordManagerPlans.filter(
      (plan) =>
        plan.type !== PlanType.Custom &&
        (!businessOwnedIsChecked || plan.canBeUsedByBusiness) &&
        (this.showFree || plan.product !== ProductType.Free) &&
        (plan.isAnnual ||
          plan.product === ProductType.Free ||
          plan.product === ProductType.TeamsStarter) &&
        (!this.currentPlan || this.currentPlan.upgradeSortOrder < plan.upgradeSortOrder) &&
        (!this.hasProvider || plan.product !== ProductType.TeamsStarter) &&
        ((!this.isProviderQualifiedFor2020Plan() && this.planIsEnabled(plan)) ||
          (this.isProviderQualifiedFor2020Plan() &&
            Allowed2020PlansForLegacyProviders.includes(plan.type))),
    );

    result.sort((planA, planB) => planA.displaySortOrder - planB.displaySortOrder);

    return result;
  }

  get selectablePlans() {
    const selectedProductType = this.formGroup.controls.product.value;
    const result =
      this.passwordManagerPlans?.filter(
        (plan) =>
          plan.product === selectedProductType &&
          ((!this.isProviderQualifiedFor2020Plan() && this.planIsEnabled(plan)) ||
            (this.isProviderQualifiedFor2020Plan() &&
              Allowed2020PlansForLegacyProviders.includes(plan.type))),
      ) || [];

    result.sort((planA, planB) => planA.displaySortOrder - planB.displaySortOrder);
    return result;
  }

  get hasProvider() {
    return this.providerId != null;
  }

  additionalStoragePriceMonthly(selectedPlan: PlanResponse) {
    if (!selectedPlan.isAnnual) {
      return selectedPlan.PasswordManager.additionalStoragePricePerGb;
    }
    return selectedPlan.PasswordManager.additionalStoragePricePerGb / 12;
  }

  seatPriceMonthly(selectedPlan: PlanResponse) {
    if (!selectedPlan.isAnnual) {
      return selectedPlan.PasswordManager.seatPrice;
    }
    return selectedPlan.PasswordManager.seatPrice / 12;
  }

  additionalStorageTotal(plan: PlanResponse): number {
    if (!plan.PasswordManager.hasAdditionalStorageOption) {
      return 0;
    }

    return (
      plan.PasswordManager.additionalStoragePricePerGb *
      Math.abs(this.formGroup.controls.additionalStorage.value || 0)
    );
  }

  passwordManagerSeatTotal(plan: PlanResponse, seats: number): number {
    if (!plan.PasswordManager.hasAdditionalSeatsOption) {
      return 0;
    }

    return plan.PasswordManager.seatPrice * Math.abs(seats || 0);
  }

  secretsManagerSeatTotal(plan: PlanResponse, seats: number): number {
    if (!plan.SecretsManager.hasAdditionalSeatsOption) {
      return 0;
    }

    return plan.SecretsManager.seatPrice * Math.abs(seats || 0);
  }

  additionalServiceAccountTotal(plan: PlanResponse): number {
    if (!plan.SecretsManager.hasAdditionalServiceAccountOption) {
      return 0;
    }

    return (
      plan.SecretsManager.additionalPricePerServiceAccount *
      Math.abs(this.secretsManagerForm.value.additionalServiceAccounts || 0)
    );
  }

  get passwordManagerSubtotal() {
    let subTotal = this.selectedPlan.PasswordManager.basePrice;
    if (
      this.selectedPlan.PasswordManager.hasAdditionalSeatsOption &&
      this.formGroup.controls.additionalSeats.value
    ) {
      subTotal += this.passwordManagerSeatTotal(
        this.selectedPlan,
        this.formGroup.value.additionalSeats,
      );
    }
    if (
      this.selectedPlan.PasswordManager.hasAdditionalStorageOption &&
      this.formGroup.controls.additionalStorage.value
    ) {
      subTotal += this.additionalStorageTotal(this.selectedPlan);
    }
    if (
      this.selectedPlan.PasswordManager.hasPremiumAccessOption &&
      this.formGroup.controls.premiumAccessAddon.value
    ) {
      subTotal += this.selectedPlan.PasswordManager.premiumAccessOptionPrice;
    }
    return subTotal - this.discount;
  }

  get secretsManagerSubtotal() {
    const plan = this.selectedSecretsManagerPlan;
    const formValues = this.secretsManagerForm.value;

    if (!this.planOffersSecretsManager || !formValues.enabled) {
      return 0;
    }

    return (
      plan.SecretsManager.basePrice +
      this.secretsManagerSeatTotal(plan, formValues.userSeats) +
      this.additionalServiceAccountTotal(plan)
    );
  }

  get freeTrial() {
    return this.selectedPlan.trialPeriodDays != null;
  }

  get taxCharges() {
    return this.taxComponent != null && this.taxComponent.taxRate != null
      ? (this.taxComponent.taxRate / 100) *
          (this.passwordManagerSubtotal + this.secretsManagerSubtotal)
      : 0;
  }

  get total() {
    return this.passwordManagerSubtotal + this.secretsManagerSubtotal + this.taxCharges || 0;
  }

  get paymentDesc() {
    if (this.acceptingSponsorship) {
      return this.i18nService.t("paymentSponsored");
    } else if (this.freeTrial && this.createOrganization) {
      return this.i18nService.t("paymentChargedWithTrial");
    } else {
      return this.i18nService.t("paymentCharged", this.i18nService.t(this.selectedPlanInterval));
    }
  }

  get secretsManagerForm() {
    return this.formGroup.controls.secretsManager;
  }

  get planOffersSecretsManager() {
    return this.selectedSecretsManagerPlan != null;
  }

  changedProduct() {
    const selectedPlan = this.selectablePlans[0];

    this.setPlanType(selectedPlan.type);
    this.handlePremiumAddonAccess(selectedPlan.PasswordManager.hasPremiumAccessOption);
    this.handleAdditionalStorage(selectedPlan.PasswordManager.hasAdditionalStorageOption);
    this.handleAdditionalSeats(selectedPlan.PasswordManager.hasAdditionalSeatsOption);
    this.handleSecretsManagerForm();
  }

  setPlanType(planType: PlanType) {
    this.formGroup.controls.plan.setValue(planType);
  }

  handlePremiumAddonAccess(hasPremiumAccessOption: boolean) {
    this.formGroup.controls.premiumAccessAddon.setValue(!hasPremiumAccessOption);
  }

  handleAdditionalStorage(selectedPlanHasAdditionalStorageOption: boolean) {
    if (!selectedPlanHasAdditionalStorageOption || !this.currentPlan) {
      this.formGroup.controls.additionalStorage.setValue(0);
      return;
    }

    if (this.organization?.maxStorageGb) {
      this.formGroup.controls.additionalStorage.setValue(
        this.organization.maxStorageGb - this.currentPlan.PasswordManager.baseStorageGb,
      );
    }
  }

  handleAdditionalSeats(selectedPlanHasAdditionalSeatsOption: boolean) {
    if (!selectedPlanHasAdditionalSeatsOption) {
      this.formGroup.controls.additionalSeats.setValue(0);
      return;
    }

    if (this.currentPlan && !this.currentPlan.PasswordManager.hasAdditionalSeatsOption) {
      this.formGroup.controls.additionalSeats.setValue(this.currentPlan.PasswordManager.baseSeats);
      return;
    }

    if (this.organization) {
      this.formGroup.controls.additionalSeats.setValue(this.organization.seats);
      return;
    }

    this.formGroup.controls.additionalSeats.setValue(1);
  }

  handleSecretsManagerForm() {
    if (this.planOffersSecretsManager) {
      this.secretsManagerForm.enable();
    }

    if (this.organization?.useSecretsManager) {
      this.secretsManagerForm.controls.enabled.setValue(true);
    }

    if (this.secretsManagerForm.controls.enabled.value) {
      this.secretsManagerForm.controls.userSeats.setValue(this.sub?.smSeats || 1);
      this.secretsManagerForm.controls.additionalServiceAccounts.setValue(
        this.sub?.smServiceAccounts - this.currentPlan.SecretsManager?.baseServiceAccount || 0,
      );
    }

    this.secretsManagerForm.updateValueAndValidity();
  }

  changedOwnedBusiness() {
    if (!this.formGroup.controls.businessOwned.value || this.selectedPlan.canBeUsedByBusiness) {
      return;
    }
    this.formGroup.controls.product.setValue(ProductType.TeamsStarter);
    this.formGroup.controls.plan.setValue(PlanType.TeamsStarter);
    this.changedProduct();
  }

  changedCountry() {
    this.paymentComponent.hideBank = this.taxComponent.taxInfo.country !== "US";
    // Bank Account payments are only available for US customers
    if (
      this.paymentComponent.hideBank &&
      this.paymentComponent.method === PaymentMethodType.BankAccount
    ) {
      this.paymentComponent.method = PaymentMethodType.Card;
      this.paymentComponent.changeMethod();
    }
  }

  cancel() {
    this.onCanceled.emit();
  }

  async submit() {
    if (this.singleOrgPolicyBlock) {
      return;
    }

    try {
      const doSubmit = async (): Promise<string> => {
        let orgId: string = null;
        if (this.createOrganization) {
          const orgKey = await this.cryptoService.makeOrgKey<OrgKey>();
          const key = orgKey[0].encryptedString;
          const collection = await this.cryptoService.encrypt(
            this.i18nService.t("defaultCollection"),
            orgKey[1],
          );
          const collectionCt = collection.encryptedString;
          const orgKeys = await this.cryptoService.makeKeyPair(orgKey[1]);

          if (this.selfHosted) {
            orgId = await this.createSelfHosted(key, collectionCt, orgKeys);
          } else {
            orgId = await this.createCloudHosted(key, collectionCt, orgKeys, orgKey[1]);
          }

          this.platformUtilsService.showToast(
            "success",
            this.i18nService.t("organizationCreated"),
            this.i18nService.t("organizationReadyToGo"),
          );
        } else {
          orgId = await this.updateOrganization(orgId);
          this.platformUtilsService.showToast(
            "success",
            null,
            this.i18nService.t("organizationUpgraded"),
          );
        }

        await this.apiService.refreshIdentityToken();
        await this.syncService.fullSync(true);

        if (!this.acceptingSponsorship && !this.isInTrialFlow) {
          // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
          // eslint-disable-next-line @typescript-eslint/no-floating-promises
          this.router.navigate(["/organizations/" + orgId]);
        }

        if (this.isInTrialFlow) {
          this.onTrialBillingSuccess.emit({
            orgId: orgId,
            subLabelText: this.billingSubLabelText(),
          });
        }

        return orgId;
      };

      this.formPromise = doSubmit();
      const organizationId = await this.formPromise;
      this.onSuccess.emit({ organizationId: organizationId });
      // TODO: No one actually listening to this message?
      this.messagingService.send("organizationCreated", { organizationId });
    } catch (e) {
      this.logService.error(e);
    }
  }

  private async updateOrganization(orgId: string) {
    const request = new OrganizationUpgradeRequest();
    request.additionalSeats = this.formGroup.controls.additionalSeats.value;
    request.additionalStorageGb = this.formGroup.controls.additionalStorage.value;
    request.premiumAccessAddon =
      this.selectedPlan.PasswordManager.hasPremiumAccessOption &&
      this.formGroup.controls.premiumAccessAddon.value;
    request.planType = this.selectedPlan.type;
    request.billingAddressCountry = this.taxComponent.taxInfo.country;
    request.billingAddressPostalCode = this.taxComponent.taxInfo.postalCode;

    // Secrets Manager
    this.buildSecretsManagerRequest(request);

    if (this.upgradeRequiresPaymentMethod) {
      const tokenResult = await this.paymentComponent.createPaymentToken();
      const paymentRequest = new PaymentRequest();
      paymentRequest.paymentToken = tokenResult[0];
      paymentRequest.paymentMethodType = tokenResult[1];
      paymentRequest.country = this.taxComponent.taxInfo.country;
      paymentRequest.postalCode = this.taxComponent.taxInfo.postalCode;
      await this.organizationApiService.updatePayment(this.organizationId, paymentRequest);
    }

    // Backfill pub/priv key if necessary
    if (!this.organization.hasPublicAndPrivateKeys) {
      const orgShareKey = await this.cryptoService.getOrgKey(this.organizationId);
      const orgKeys = await this.cryptoService.makeKeyPair(orgShareKey);
      request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
    }

    const result = await this.organizationApiService.upgrade(this.organizationId, request);
    if (!result.success && result.paymentIntentClientSecret != null) {
      await this.paymentComponent.handleStripeCardPayment(result.paymentIntentClientSecret, null);
    }
    return this.organizationId;
  }

  private async createCloudHosted(
    key: string,
    collectionCt: string,
    orgKeys: [string, EncString],
    orgKey: SymmetricCryptoKey,
  ) {
    const request = new OrganizationCreateRequest();
    request.key = key;
    request.collectionName = collectionCt;
    request.name = this.formGroup.controls.name.value;
    request.billingEmail = this.formGroup.controls.billingEmail.value;
    request.initiationPath = "New organization creation in-product";
    request.keys = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);

    if (this.selectedPlan.type === PlanType.Free) {
      request.planType = PlanType.Free;
    } else {
      const tokenResult = await this.paymentComponent.createPaymentToken();

      request.paymentToken = tokenResult[0];
      request.paymentMethodType = tokenResult[1];
      request.additionalSeats = this.formGroup.controls.additionalSeats.value;
      request.additionalStorageGb = this.formGroup.controls.additionalStorage.value;
      request.premiumAccessAddon =
        this.selectedPlan.PasswordManager.hasPremiumAccessOption &&
        this.formGroup.controls.premiumAccessAddon.value;
      request.planType = this.selectedPlan.type;
      request.billingAddressPostalCode = this.taxComponent.taxInfo.postalCode;
      request.billingAddressCountry = this.taxComponent.taxInfo.country;
      if (this.taxComponent.taxInfo.includeTaxId) {
        request.taxIdNumber = this.taxComponent.taxInfo.taxId;
        request.billingAddressLine1 = this.taxComponent.taxInfo.line1;
        request.billingAddressLine2 = this.taxComponent.taxInfo.line2;
        request.billingAddressCity = this.taxComponent.taxInfo.city;
        request.billingAddressState = this.taxComponent.taxInfo.state;
      }
    }

    // Secrets Manager
    this.buildSecretsManagerRequest(request);

    if (this.hasProvider) {
      const providerRequest = new ProviderOrganizationCreateRequest(
        this.formGroup.controls.clientOwnerEmail.value,
        request,
      );
      const providerKey = await this.cryptoService.getProviderKey(this.providerId);
      providerRequest.organizationCreateRequest.key = (
        await this.cryptoService.encrypt(orgKey.key, providerKey)
      ).encryptedString;
      const orgId = (
        await this.apiService.postProviderCreateOrganization(this.providerId, providerRequest)
      ).organizationId;

      return orgId;
    } else {
      return (await this.organizationApiService.create(request)).id;
    }
  }

  private async createSelfHosted(key: string, collectionCt: string, orgKeys: [string, EncString]) {
    const fileEl = document.getElementById("file") as HTMLInputElement;
    const files = fileEl.files;
    if (files == null || files.length === 0) {
      throw new Error(this.i18nService.t("selectFile"));
    }

    const fd = new FormData();
    fd.append("license", files[0]);
    fd.append("key", key);
    fd.append("collectionName", collectionCt);
    const response = await this.organizationApiService.createLicense(fd);
    const orgId = response.id;

    await this.apiService.refreshIdentityToken();

    // Org Keys live outside of the OrganizationLicense - add the keys to the org here
    const request = new OrganizationKeysRequest(orgKeys[0], orgKeys[1].encryptedString);
    await this.organizationApiService.updateKeys(orgId, request);

    return orgId;
  }

  private billingSubLabelText(): string {
    const selectedPlan = this.selectedPlan;
    const price =
      selectedPlan.PasswordManager.basePrice === 0
        ? selectedPlan.PasswordManager.seatPrice
        : selectedPlan.PasswordManager.basePrice;
    let text = "";

    if (selectedPlan.isAnnual) {
      text += `${this.i18nService.t("annual")} ($${price}/${this.i18nService.t("yr")})`;
    } else {
      text += `${this.i18nService.t("monthly")} ($${price}/${this.i18nService.t("monthAbbr")})`;
    }

    return text;
  }

  private buildSecretsManagerRequest(
    request: OrganizationCreateRequest | OrganizationUpgradeRequest,
  ): void {
    const formValues = this.secretsManagerForm.value;

    request.useSecretsManager = this.planOffersSecretsManager && formValues.enabled;

    if (!request.useSecretsManager) {
      return;
    }

    if (this.selectedSecretsManagerPlan.SecretsManager.hasAdditionalSeatsOption) {
      request.additionalSmSeats = formValues.userSeats;
    }

    if (this.selectedSecretsManagerPlan.SecretsManager.hasAdditionalServiceAccountOption) {
      request.additionalServiceAccounts = formValues.additionalServiceAccounts;
    }
  }

  private upgradeFlowPrefillForm() {
    if (this.acceptingSponsorship) {
      this.formGroup.controls.product.setValue(ProductType.Families);
      this.changedProduct();
      return;
    }

    if (this.currentPlan && this.currentPlan.product !== ProductType.Enterprise) {
      const upgradedPlan = this.passwordManagerPlans.find((plan) =>
        this.currentPlan.product === ProductType.Free
          ? plan.type === PlanType.FamiliesAnnually
          : plan.upgradeSortOrder == this.currentPlan.upgradeSortOrder + 1,
      );

      this.plan = upgradedPlan.type;
      this.product = upgradedPlan.product;
      this.changedProduct();
    }
  }

  private planIsEnabled(plan: PlanResponse) {
    return !plan.disabled && !plan.legacyYear;
  }
}
