import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
import { APP_ICONS, type AppIconName, type LucideIconNode } from './icon-registry';

/**
 * Single entry point for every icon in the app. Renders a Lucide icon by
 * canonical name (see icon-registry.ts) so every screen uses one icon family
 * at one consistent size/stroke-width by default.
 *
 * Renders directly from transcribed Lucide node data (see icon-registry.ts)
 * instead of using @lucide/angular's runtime, matching the shape switch and
 * host attributes of Lucide's own LucideIconBase/LucideDynamicIcon so output
 * is pixel-identical.
 *
 * Decorative by default (aria-hidden). Pass `ariaLabel` only when the icon
 * itself carries meaning with no adjacent text (e.g. inside an icon-only
 * button) - the label belongs on the interactive element when there is one.
 */
@Component({
  selector: 'app-icon',
  standalone: true,
  template: `
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 24 24"
      fill="none"
      stroke-linecap="round"
      stroke-linejoin="round"
      class="lucide"
      [attr.width]="size()"
      [attr.height]="size()"
      [attr.stroke]="color()"
      [attr.stroke-width]="strokeWidth()"
      [attr.role]="ariaLabel() ? 'img' : null"
      [attr.aria-label]="ariaLabel()"
      [attr.aria-hidden]="ariaLabel() ? null : 'true'"
    >
      @if (ariaLabel(); as label) {
        <title>{{ label }}</title>
      }
      @for (node of nodes(); track $index) {
        @let attrs = node[1];
        @switch (node[0]) {
          @case ('path') {
            <path [attr.d]="attrs['d']" [attr.fill]="attrs['fill']" />
          }
          @case ('line') {
            <line [attr.x1]="attrs['x1']" [attr.x2]="attrs['x2']" [attr.y1]="attrs['y1']" [attr.y2]="attrs['y2']" />
          }
          @case ('polygon') {
            <polygon [attr.points]="attrs['points']" />
          }
          @case ('polyline') {
            <polyline [attr.points]="attrs['points']" />
          }
          @case ('circle') {
            <circle [attr.cx]="attrs['cx']" [attr.cy]="attrs['cy']" [attr.r]="attrs['r']" [attr.fill]="attrs['fill']" />
          }
          @case ('ellipse') {
            <ellipse [attr.cx]="attrs['cx']" [attr.cy]="attrs['cy']" [attr.rx]="attrs['rx']" [attr.ry]="attrs['ry']" />
          }
          @case ('rect') {
            <rect
              [attr.x]="attrs['x']"
              [attr.y]="attrs['y']"
              [attr.width]="attrs['width']"
              [attr.height]="attrs['height']"
              [attr.rx]="attrs['rx']"
              [attr.ry]="attrs['ry']"
            />
          }
        }
      }
    </svg>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    class: 'app-icon',
    '[style.display]': "'inline-flex'"
  }
})
export class IconComponent {
  readonly name = input.required<AppIconName>();
  readonly size = input<number>(20);
  readonly color = input<string>('currentColor');
  readonly strokeWidth = input<number>(2);
  readonly ariaLabel = input<string | null>(null);

  // `APP_ICONS` is declared `as const satisfies ...` so per-icon tuple types stay
  // literal (keeps `AppIconName` a precise key union for callers); widen here at
  // the single consumption point instead of loosening the registry's own typing.
  protected readonly nodes = computed(
    () => APP_ICONS[this.name()] as readonly LucideIconNode[]
  );
}
