import {
  Directive,
  ViewContainerRef,
  TemplateRef,
  inject,
  input,
  effect,
  ComponentRef,
  untracked,
  EmbeddedViewRef,
} from '@angular/core';
import { SkeletonLoaderComponent } from './skeleton-loader.component';

/**
 * Structural directive that conditionally replaces its content with a skeleton loader.
 *
 * @example
 * <div *uiSkeletonLoader="isLoading">Content to hide while loading</div>
 *
 * @example
 * <div *uiSkeletonLoader="isLoading; width: '100px'; height: '20px'">Content</div>
 */
@Directive({
  selector: '[uiSkeletonLoader]',
})
export class SkeletonLoaderDirective {
  #viewContainerRef = inject(ViewContainerRef);
  #templateRef = inject(TemplateRef);

  private componentRef: ComponentRef<SkeletonLoaderComponent> | null = null;
  private embeddedViewRef: EmbeddedViewRef<unknown> | null = null;

  uiSkeletonLoader = input<boolean>(false);

  uiSkeletonLoaderWidth = input<string | undefined>(undefined);

  uiSkeletonLoaderHeight = input<string | undefined>(undefined);

  render = effect(() => {
    const condition = this.uiSkeletonLoader();

    if (condition && !this.componentRef) {
      // Create the skeleton loader when condition is true and view isn't created
      this.#viewContainerRef.clear();
      this.componentRef = this.#viewContainerRef.createComponent(
        SkeletonLoaderComponent,
      );

      untracked(() => {
        this.applyStyles();
      });

      this.embeddedViewRef = null; // Clear the embedded view reference
    } else if (!condition && !this.embeddedViewRef) {
      // Show original content when condition is false
      this.#viewContainerRef.clear();
      this.embeddedViewRef = this.#viewContainerRef.createEmbeddedView(
        this.#templateRef,
      );

      this.componentRef = null; // Clear the component reference
    }
  });

  updateStyles = effect(() => {
    this.applyStyles();
  });

  applyStyles() {
    if (this.componentRef) {
      const width = this.uiSkeletonLoaderWidth() || 'inherit';
      const height = this.uiSkeletonLoaderHeight() || 'inherit';
      const element: HTMLElement | undefined =
        this.componentRef?.location?.nativeElement;
      if (element) {
        element.style.width = width;
        element.style.height = height;
      }
    }
  }
}
