import {
  Directive,
  effect,
  inject,
  input,
  TemplateRef,
  ViewContainerRef,
} from '@angular/core';
import { RoleService } from './role.service';
import { Role } from './role';

/**
 * Structural directive for role-based conditional rendering using Angular signals
 *
 * @example
 * ```html
 * <!-- Show content if user has role -->
 * <div *ifRole="Role.Store">Store content</div>
 *
 * <!-- Show content if user has multiple roles -->
 * <div *ifRole="[Role.Store, Role.CallCenter]">Multiple roles</div>
 *
 * <!-- Show alternate content if user doesn't have role -->
 * <div *ifRole="Role.Store; else noAccess">Store content</div>
 * <ng-template #noAccess>No access</ng-template>
 *
 * <!-- Show content if user does NOT have role -->
 * <div *ifNotRole="Role.CallCenter">Non-CallCenter content</div>
 * ```
 */
@Directive({
  selector: '[ifRole],[ifRoleElse],[ifNotRole],[ifNotRoleElse]',
  standalone: true,
})
export class IfRoleDirective {
  private readonly _templateRef = inject(TemplateRef<{ $implicit: Role | Role[] }>);
  private readonly _viewContainer = inject(ViewContainerRef);
  private readonly _roleService = inject(RoleService);

  /**
   * Role(s) required to show the template
   */
  readonly ifRole = input<Role | Role[]>();

  /**
   * Alternative template to show if user doesn't have ifRole
   */
  readonly ifRoleElse = input<TemplateRef<unknown>>();

  /**
   * Role(s) that should NOT be present to show the template
   */
  readonly ifNotRole = input<Role | Role[]>();

  /**
   * Alternative template to show if user has ifNotRole
   */
  readonly ifNotRoleElse = input<TemplateRef<unknown>>();

  constructor() {
    // Use effect to reactively update the view when inputs change
    effect(() => {
      this.render();
    });
  }

  private get renderTemplateRef(): boolean {
    const role = this.ifRole();
    const notRole = this.ifNotRole();

    if (role) {
      return this._roleService.hasRole(role);
    }
    if (notRole) {
      return !this._roleService.hasRole(notRole);
    }
    return false;
  }

  private get elseTemplateRef(): TemplateRef<unknown> | undefined {
    return this.ifRoleElse() || this.ifNotRoleElse();
  }

  private render() {
    if (this.renderTemplateRef) {
      this._viewContainer.clear();
      this._viewContainer.createEmbeddedView(this._templateRef, this.getContext());
      return;
    }

    if (this.elseTemplateRef) {
      this._viewContainer.clear();
      this._viewContainer.createEmbeddedView(this.elseTemplateRef, this.getContext());
      return;
    }

    this._viewContainer.clear();
  }

  private getContext(): { $implicit: Role | Role[] | undefined } {
    return {
      $implicit: this.ifRole() || this.ifNotRole(),
    };
  }
}
