import { Injectable, signal } from '@angular/core';

import { ThemeLayoutContainerDefinition, ThemeRegistryEntry } from '../../domain/models/theme.model';
import {
  THEME_LAYOUT_CONTAINERS,
  THEME_REGISTRY,
  findThemeLayoutContainer,
  findThemeRegistryEntry
} from '../../domain/logic/theme-registry.logic';

@Injectable({ providedIn: 'root' })
export class ThemeRegistryService {
  private readonly mountedCounts = signal<Record<string, number>>({});
  private readonly mountedHosts = new Map<string, Set<HTMLElement>>();

  entries(): readonly ThemeRegistryEntry[] {
    return THEME_REGISTRY;
  }

  layoutContainers(): readonly ThemeLayoutContainerDefinition[] {
    return THEME_LAYOUT_CONTAINERS;
  }

  mountedKeyCounts() {
    return this.mountedCounts();
  }

  getDefinition(key: string | null | undefined): ThemeRegistryEntry | null {
    return key
      ? findThemeRegistryEntry(key)
      : null;
  }

  getContainer(key: string | null | undefined): ThemeLayoutContainerDefinition | null {
    return key
      ? findThemeLayoutContainer(key)
      : null;
  }

  registerHost(key: string, host: HTMLElement): void {
    const existingHosts = this.mountedHosts.get(key) ?? new Set<HTMLElement>();

    existingHosts.add(host);
    this.mountedHosts.set(key, existingHosts);
    this.syncMountedCounts();
  }

  unregisterHost(key: string, host: HTMLElement): void {
    const existingHosts = this.mountedHosts.get(key);

    if (!existingHosts) {
      return;
    }

    existingHosts.delete(host);

    if (existingHosts.size === 0) {
      this.mountedHosts.delete(key);
    }

    this.syncMountedCounts();
  }

  firstMountedHost(key: string): HTMLElement | null {
    const hosts = this.mountedHosts.get(key);

    return hosts
      ? Array.from(hosts)[0] ?? null
      : null;
  }

  isMounted(key: string): boolean {
    return (this.mountedCounts()[key] ?? 0) > 0;
  }

  private syncMountedCounts(): void {
    const nextCounts: Record<string, number> = {};

    for (const [key, hosts] of this.mountedHosts.entries()) {
      nextCounts[key] = hosts.size;
    }

    this.mountedCounts.set(nextCounts);
  }
}
