import {
  ChangeDetectionStrategy,
  Component,
  computed,
  DestroyRef,
  inject,
  signal
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr';
import { catchError, finalize, of } from 'rxjs';
import {
  OnboardingStep,
  OnboardingStepper
} from './components/onboarding-stepper/onboarding-stepper';
import { OrganizationBasicsStepComponent } from './steps/organization-basics/organization-basics';
import { OrganizationOnboardingStateService } from './services/organization-onboarding-state.service';
import { OrganizationOnboardingService } from './services/organization-onboarding.service';

@Component({
  selector: 'app-organization-onboarding',
  standalone: true,
  imports: [OnboardingStepper, OrganizationBasicsStepComponent],
  templateUrl: './organization-onboarding.html',
  styleUrl: './organization-onboarding.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [OrganizationOnboardingStateService, OrganizationOnboardingService]
})
export class OrganizationOnboarding {
  private readonly destroyRef = inject(DestroyRef);
  private readonly router = inject(Router);
  private readonly toastr = inject(ToastrService);
  private readonly stateService = inject(OrganizationOnboardingStateService);
  private readonly onboardingService = inject(OrganizationOnboardingService);

  readonly steps: readonly OnboardingStep[] = this.stateService.createStepDefinitions();

  readonly savingDraft = signal(false);
  readonly finishing = signal(false);

  private basicsStep?: OrganizationBasicsStepComponent;

  readonly currentStepIndex = this.stateService.currentStepIndex;
  readonly completedStepIndexes = this.stateService.completedStepIndexes;

  readonly currentStep = computed(
    () => this.steps[this.currentStepIndex()]
  );

  readonly navigationDisabled = computed(
    () => this.savingDraft() || this.finishing()
  );

  constructor() {
    this.onboardingService.loadDraft()
      .pipe(
        catchError(() => {
          this.toastr.error('Unable to restore the onboarding draft.', 'Draft restore failed');
          return of(null);
        }),
        takeUntilDestroyed(this.destroyRef)
      )
      .subscribe(draft => {
        if (!draft) {
          return;
        }

        this.stateService.restoreDraft(draft);
      });
  }

  registerBasicsStep(component: OrganizationBasicsStepComponent): void {
    this.basicsStep = component;
    const basicsDraft = this.stateService.onboardingDraft().basics;

    if (basicsDraft) {
      component.patchValue(basicsDraft);
    }
  }

  onStepSelected(index: number): void {
    if (!this.stateService.canOpenStep(index)) {
      return;
    }

    this.stateService.setCurrentStepIndex(index);
  }

  onBack(): void {
    const currentIndex = this.currentStepIndex();

    if (currentIndex <= 0) {
      return;
    }

    this.stateService.setCurrentStepIndex(currentIndex - 1);
  }

  onNext(): void {
    const currentIndex = this.currentStepIndex();

    if (currentIndex >= this.steps.length - 1) {
      return;
    }

    if (currentIndex === 0) {
      if (!this.basicsStep?.validate()) {
        this.stateService.unmarkStepCompleted(currentIndex);
        return;
      }

      this.stateService.updateBasics(this.basicsStep.getValue());
    }

    this.stateService.markStepCompleted(currentIndex);
    this.stateService.setCurrentStepIndex(currentIndex + 1);
  }

  onSaveDraft(): void {
    if (this.savingDraft()) {
      return;
    }

    if (this.currentStepIndex() === 0 && this.basicsStep) {
      this.stateService.updateBasicsDraft(this.basicsStep.getDraftValue());
    }

    this.savingDraft.set(true);

    this.onboardingService.saveDraft(this.stateService.buildDraft())
      .pipe(
        finalize(() => {
          this.savingDraft.set(false);
        }),
        takeUntilDestroyed(this.destroyRef)
      )
      .subscribe({
        next: () => {
          this.toastr.success('Onboarding draft saved successfully.', 'Draft saved');
        },
        error: () => {
          this.toastr.error('Unable to save the onboarding draft.', 'Draft save failed');
        }
      });
  }

  onFinish(): void {
    if (this.finishing()) {
      return;
    }

    this.finishing.set(true);

    queueMicrotask(() => {
      this.finishing.set(false);
    });
  }

  onCancel(): void {
    this.stateService.clear();
    void this.router.navigate(['/configuration/organizations']);
  }
}