import { useEffect, useState } from 'preact/hooks';
import type { AsukaModuleComponent } from './modules';

export interface AsukaImageProviderDefinition {
  id: string;
  label: string;
  icon?: string;
  order?: number;
  render: AsukaModuleComponent;
  licenseFeature?: string;
  permissionFlags?: string[];
  /**
   * Optional configuration path checked against `integrations`.
   * Providers with `hideWhenIntegrationMissing` only appear when at least
   * one configured integration path contains a non-empty value.
   */
  integrationPath?: string | string[];
  hideWhenIntegrationMissing?: boolean;
  group?: 'core' | 'premium' | string;
}

export type AsukaImageProviderRegistryListener = () => void;

const registry = new Map<string, AsukaImageProviderDefinition>();
let registryVersion = 0;
const listeners = new Set<AsukaImageProviderRegistryListener>();

function emitRegistryChanged(): void {
  registryVersion += 1;
  listeners.forEach((listener) => {
    try { listener(); } catch {}
  });
}

export function subscribeImageProviderRegistry(listener: AsukaImageProviderRegistryListener): () => void {
  listeners.add(listener);
  return () => listeners.delete(listener);
}

export function notifyImageProviderRegistryChanged(): void {
  emitRegistryChanged();
}

export function useImageProviderRegistryVersion(): number {
  const [version, setVersion] = useState(registryVersion);
  useEffect(() => subscribeImageProviderRegistry(() => setVersion(registryVersion)), []);
  return version;
}

export function registerImageProvider(def: AsukaImageProviderDefinition): void {
  registry.set(def.id, def);
  emitRegistryChanged();
}

export function getImageProvider(id: string | null | undefined): AsukaImageProviderDefinition | undefined {
  if (!id) return undefined;
  return registry.get(id);
}

export function getAllImageProviders(): AsukaImageProviderDefinition[] {
  return Array.from(registry.values()).sort((a, b) => {
    const orderDiff = Number(a.order ?? 0) - Number(b.order ?? 0);
    if (orderDiff !== 0) return orderDiff;
    return a.label.localeCompare(b.label);
  });
}

function getNestedValue(input: unknown, path: string): unknown {
  return path.split('.').reduce((acc, part) => {
    if (!acc || typeof acc !== 'object') return undefined;
    return (acc as Record<string, unknown>)[part];
  }, input as unknown);
}

export function isImageProviderAvailable(
  def: AsukaImageProviderDefinition,
  input: {
    permissions?: Record<string, unknown> | null;
    integrations?: Record<string, unknown> | null;
    canUseLicenseFeature?: ((feature: string) => boolean) | null;
  },
): boolean {
  if (Array.isArray(def.permissionFlags) && def.permissionFlags.length > 0) {
    const ok = def.permissionFlags.every((flag) => Boolean(input.permissions?.[flag]));
    if (!ok) return false;
  }

  if (def.licenseFeature && input.canUseLicenseFeature && input.canUseLicenseFeature(def.licenseFeature) === false) {
    return false;
  }

  const paths = Array.isArray(def.integrationPath)
    ? def.integrationPath
    : typeof def.integrationPath === 'string' && def.integrationPath.trim()
      ? [def.integrationPath]
      : [];

  if (def.hideWhenIntegrationMissing === true && paths.length > 0) {
    const hasIntegration = paths.some((path) => {
      const value = getNestedValue(input.integrations ?? {}, path);
      return Boolean(String(value ?? '').trim());
    });
    if (!hasIntegration) return false;
  }

  return true;
}
