import {
  ChangeDetectionStrategy,
  Component,
  computed,
  inject,
  signal,
} from '@angular/core';
import { DialogContentDirective } from './dialog-content.directive';
import {
  DIALOG_CLASS_LIST,
  DIALOG_CONTENT,
  DIALOG_TITLE,
  DISPLAY_DIALOG_CLOSE,
} from './tokens';
import { ComponentType } from '@angular/cdk/portal';
import { NgComponentOutlet } from '@angular/common';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { isaActionClose } from '@isa/icons';
import { DialogRef } from '@angular/cdk/dialog';

/**
 * Base dialog component that serves as a container for dialog content
 * Handles the outer dialog shell including title and content projection
 *
 * @template D Type of data passed to the dialog
 * @template R Type of result returned from the dialog
 * @template C Type of content component displayed in the dialog
 */
@Component({
  selector: 'ui-dialog',
  templateUrl: './dialog.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [NgComponentOutlet, NgIcon],
  host: {
    '[class]': 'classes()',
  },
  providers: [provideIcons({ isaActionClose })],
})
export class DialogComponent<D, R, C extends DialogContentDirective<D, R>> {
  /** The title to display at the top of the dialog */
  title = signal(inject(DIALOG_TITLE));

  /** The component type to instantiate as the dialog content */
  readonly component = inject(DIALOG_CONTENT) as ComponentType<C>;

  /** Reference to the dialog instance for closing the dialog */
  private readonly dialogRef = inject(DialogRef<R, DialogComponent<D, R, C>>);

  /**
   * Signal that determines whether the close button should be displayed
   * This is controlled by an injection token, allowing for flexible configuration
   */
  readonly displayCloseButton = signal(
    inject(DISPLAY_DIALOG_CLOSE, {
      optional: true,
    }),
  );

  /** Additional CSS classes provided via injection */
  private readonly classList =
    inject(DIALOG_CLASS_LIST, { optional: true }) ?? [];

  /**
   * Computed property that combines the base dialog class with any additional classes
   * This allows for dynamic styling of the dialog based on external configuration
   *
   * @return An array of CSS class names to apply to the dialog element
   */
  classes = computed(() => {
    return ['ui-dialog', ...this.classList];
  });

  /**
   * Closes the dialog without returning any result
   * This is typically called when the user clicks the close button (X)
   */
  close(): void {
    this.dialogRef.close();
  }
}
