import 'server-only';

import type { InstallationProfile } from './installation-profile';
import { FoundationSetupPlugin } from './foundation/foundation-plugin';
import { CrmSetupPlugin } from './crm/crm-setup-plugin';
import type {
  GoldenDatasetDefinition,
  ResetScopeDefinition,
  ReseedTargetDefinition,
  SetupPlugin,
  SetupReadinessCheck,
  SetupTemplateDefinition,
  SetupVerificationCheck,
  SetupWizardStep
} from './plugin-types';

class SetupPluginRegistry {
  private plugins = new Map<string, SetupPlugin>();

  registerPlugin(plugin: SetupPlugin) {
    if (this.plugins.has(plugin.id)) {
      throw new Error(`Setup plugin already registered: ${plugin.id}`);
    }
    if (plugin.dependencies.includes(plugin.id)) {
      throw new Error(`Setup plugin cannot depend on itself: ${plugin.id}`);
    }
    this.plugins.set(plugin.id, plugin);
  }

  getPlugins() {
    return Array.from(this.plugins.values());
  }

  resolveInstallationProfiles(): InstallationProfile[] {
    const profiles = this.getPlugins().flatMap((plugin) => plugin.installationProfiles());
    const byId = new Map<string, InstallationProfile>();
    profiles.forEach((profile) => {
      if (!byId.has(profile.id)) byId.set(profile.id, profile);
    });
    return Array.from(byId.values());
  }

  resolveInstallationProfile(profileId = 'crm_demo') {
    return this.resolveInstallationProfiles().find((profile) => profile.id === profileId) ?? null;
  }

  resolveEnabledPlugins(profileId = 'crm_demo') {
    const profile = this.resolveInstallationProfile(profileId);
    if (!profile) return this.getPlugins();

    const enabled = new Set(profile.enabledPluginIds);
    enabled.add('foundation');
    return this.getPlugins().filter((plugin) => enabled.has(plugin.id));
  }

  resolveTemplates(profileId = 'crm_demo'): SetupTemplateDefinition[] {
    const profile = this.resolveInstallationProfile(profileId);
    const required = new Set(profile?.requiredTemplates ?? []);
    const templates = this.resolveEnabledPlugins(profileId).flatMap((plugin) => plugin.templates());

    return templates
      .map((template) => ({
        ...template,
        profiles: template.profiles.length ? template.profiles : [profileId],
        supported: template.supported && (!profile || required.size === 0 || required.has(template.file))
      }))
      .toSorted((a, b) => a.importOrder - b.importOrder);
  }

  resolveWizardSteps(profileId = 'crm_demo'): SetupWizardStep[] {
    const profile = this.resolveInstallationProfile(profileId);
    const profileStepKeys = new Set(profile?.wizardSteps ?? []);
    const steps = this.resolveEnabledPlugins(profileId).flatMap((plugin) => plugin.wizardSteps());
    const baseSteps = steps.filter((step) => profileStepKeys.size === 0 || profileStepKeys.has(step.key));
    const extras = steps.filter((step) => !profileStepKeys.has(step.key) && step.key.startsWith('crm-'));
    return [...baseSteps, ...extras];
  }

  resolveReadinessChecks(profileId = 'crm_demo'): SetupReadinessCheck[] {
    return this.resolveEnabledPlugins(profileId).flatMap((plugin) => plugin.readinessChecks());
  }

  resolveVerificationChecks(profileId = 'crm_demo'): SetupVerificationCheck[] {
    return this.resolveEnabledPlugins(profileId).flatMap((plugin) => plugin.verificationChecks());
  }

  resolveResetScopes(profileId = 'crm_demo'): ResetScopeDefinition[] {
    const profile = this.resolveInstallationProfile(profileId);
    const allowed = new Set(profile?.resetScopes ?? []);
    return this.resolveEnabledPlugins(profileId)
      .flatMap((plugin) => plugin.resetScopes())
      .filter((scope) => allowed.size === 0 || allowed.has(scope.key));
  }

  resolveReseedTargets(profileId = 'crm_demo'): ReseedTargetDefinition[] {
    const profile = this.resolveInstallationProfile(profileId);
    const allowed = new Set(profile?.reseedTargets ?? []);
    return this.resolveEnabledPlugins(profileId)
      .flatMap((plugin) => plugin.reseedTargets())
      .filter((target) => allowed.size === 0 || allowed.has(target.key));
  }

  resolveGoldenDatasets(profileId = 'crm_demo'): GoldenDatasetDefinition[] {
    return this.resolveEnabledPlugins(profileId).flatMap((plugin) => plugin.goldenDatasets());
  }
}

const registry = new SetupPluginRegistry();
registry.registerPlugin(new FoundationSetupPlugin());
registry.registerPlugin(new CrmSetupPlugin());

export function getSetupPluginRegistry() {
  return registry;
}

export function getInstallationProfileBundle(profileId = 'crm_demo') {
  const selectedProfile = registry.resolveInstallationProfile(profileId) ?? registry.resolveInstallationProfile('crm_demo');
  const selectedProfileId = selectedProfile?.id ?? 'crm_demo';

  return {
    selectedProfile,
    profiles: registry.resolveInstallationProfiles(),
    plugins: registry.getPlugins().map((plugin) => ({
      id: plugin.id,
      version: plugin.version,
      displayName: plugin.displayName,
      description: plugin.description,
      dependencies: plugin.dependencies
    })),
    templates: registry.resolveTemplates(selectedProfileId),
    wizardSteps: registry.resolveWizardSteps(selectedProfileId),
    readinessChecks: registry.resolveReadinessChecks(selectedProfileId),
    verificationChecks: registry.resolveVerificationChecks(selectedProfileId),
    resetScopes: registry.resolveResetScopes(selectedProfileId),
    reseedTargets: registry.resolveReseedTargets(selectedProfileId),
    goldenDatasets: registry.resolveGoldenDatasets(selectedProfileId)
  };
}
