/**
 * Copyright IBM Corp. 2016, 2025
 * SPDX-License-Identifier: BUSL-1.1
 */

import { service } from '@ember/service';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import Component from '@glimmer/component';
import { SecurityPolicy } from 'vault/components/wizard/namespaces/step-1';
import { CreationMethod } from 'vault/components/wizard/namespaces/step-3';
import { WIZARD_ID_MAP } from 'vault/utils/constants/wizard';

import type ApiService from 'vault/services/api';
import type Block from 'vault/components/wizard/namespaces/step-2';
import type FlashMessageService from 'vault/services/flash-messages';
import type NamespaceService from 'vault/services/namespace';
import type RouterService from '@ember/routing/router-service';
import type WizardService from 'vault/services/wizard';

const DEFAULT_STEPS = [
  { title: 'Select setup', component: 'wizard/namespaces/step-1' },
  { title: 'Map out namespaces', component: 'wizard/namespaces/step-2' },
  { title: 'Apply changes', component: 'wizard/namespaces/step-3' },
];

interface Args {
  isIntroModal: boolean;
  onRefresh: CallableFunction;
  onFlexiblePolicyComplete: CallableFunction;
}

interface WizardState {
  securityPolicyChoice: SecurityPolicy | null;
  namespacePaths: string[] | null;
  namespaceBlocks: Block[] | null;
  creationMethod: CreationMethod | null;
  codeSnippet: string | null;
}

export default class WizardNamespacesWizardComponent extends Component<Args> {
  @service declare readonly api: ApiService;
  @service declare readonly router: RouterService;
  @service declare readonly flashMessages: FlashMessageService;
  @service declare readonly wizard: WizardService;
  @service declare namespace: NamespaceService;

  @tracked currentStep = 0;
  @tracked steps = DEFAULT_STEPS;
  @tracked wizardState: WizardState = {
    securityPolicyChoice: null,
    namespacePaths: null,
    namespaceBlocks: null,
    creationMethod: null,
    codeSnippet: null,
  };

  methods = CreationMethod;
  policy = SecurityPolicy;

  wizardId = WIZARD_ID_MAP.namespace;

  // Whether the current step requirements have been met to proceed to the next step
  get canProceed() {
    switch (this.currentStep) {
      case 0: // Step 1 - requires security policy choice
        return Boolean(this.wizardState.securityPolicyChoice);
      case 1: // Step 2 - requires valid namespace inputs
        return Boolean(this.wizardState.namespacePaths);
      case 2: // Step 3 - no validation is needed
        return true;
      default:
        return true;
    }
  }

  get isFinalStep() {
    return this.currentStep === this.steps.length - 1;
  }

  get shouldShowExitButton() {
    // Show exit button unless we're on the final step with UI creation method
    return !(this.wizardState.creationMethod === CreationMethod.UI && this.isFinalStep);
  }

  get exitText() {
    return this.isFinalStep && this.wizardState.securityPolicyChoice === SecurityPolicy.STRICT
      ? 'Done & Exit'
      : 'Exit';
  }

  updateSteps() {
    if (this.wizardState.securityPolicyChoice === SecurityPolicy.FLEXIBLE) {
      this.steps = [
        { title: 'Select setup', component: 'wizard/namespaces/step-1' },
        { title: 'Apply changes', component: 'wizard/namespaces/step-3' },
      ];
    } else {
      this.steps = DEFAULT_STEPS;
    }
  }

  @action
  onStepChange(step: number) {
    this.currentStep = step;
    // if user policy selection changes which steps we show, update upon page navigation
    // instead of flashing the changes when toggling
    this.updateSteps();
  }

  @action
  updateWizardState(key: string, value: unknown) {
    this.wizardState = {
      ...this.wizardState,
      [key]: value,
    };
  }

  @action
  async onDone() {
    await this.onDismiss();
    this.args.onFlexiblePolicyComplete();
    this.flashMessages.success(`Your current setup is 1 namespace.`, { title: 'Guided start complete' });
  }

  @action
  async onDismiss() {
    this.wizard.dismiss(this.wizardId);
    await this.args.onRefresh();
  }

  @action
  async onSubmit() {
    switch (this.wizardState.creationMethod) {
      case CreationMethod.UI:
        await this.createNamespacesFromWizard();
        break;
      default:
        // The other creation methods require the user to execute the commands on their own
        // In these cases, there is no submit button
        break;
    }
  }

  @action
  onIntroChange(visible: boolean) {
    this.wizard.setIntroVisible(this.wizardId, visible);
  }

  @action
  async createNamespacesFromWizard() {
    try {
      const { namespacePaths } = this.wizardState;
      if (!namespacePaths) return;

      for (const nsPath of namespacePaths) {
        const parts = nsPath.split('/');
        const namespaceName = parts[parts.length - 1] as string;
        const parentPath = parts.length > 1 ? parts.slice(0, -1).join('/') : undefined;
        // this provides the full nested path for the header
        const fullPath = parentPath ? this.namespace.path + '/' + parentPath : undefined;
        await this.createNamespace(namespaceName, fullPath);
      }

      this.flashMessages.success('Your new configuration has been applied.', { title: 'Namespaces created' });
    } catch (error) {
      const { message } = await this.api.parseError(error);
      this.flashMessages.danger(`Error creating namespaces: ${message}`);
    } finally {
      this.onDismiss();
    }
  }

  @action
  switchNamespace(targetNamespace: string) {
    this.router.transitionTo('vault.cluster.dashboard', {
      queryParams: { namespace: targetNamespace },
    });
  }

  async createNamespace(path: string, header?: string) {
    const headers = header ? this.api.buildHeaders({ namespace: header }) : undefined;
    await this.api.sys.systemWriteNamespacesPath(path, {}, headers);
  }
}
