import { TranslateService } from '../../../i18n/translate.service';
import { BootstrapConfig } from '../../../shared/models/config';
import { WidgetManifestFile } from '../../../widgets/contracts/widget-manifest.contract';
import { validateAgainstSchemaLite } from '../../project-editor/schema/validators/primitives';
import { DiagnosticEntry } from '../models/diagnostics.model';

const KNOWN_LAYOUTS = new Set(['default', 'sidebar-left', 'carousel-home', 'minimal']);

export class BootstrapDiagnosticsValidator {
  validate(
    bootstrap: BootstrapConfig | null,
    manifest: WidgetManifestFile | null,
    availableRoutes: string[],
    translate: TranslateService
  ): DiagnosticEntry[] {
    const entries: DiagnosticEntry[] = [];

    if (!bootstrap) {
      entries.push({
        code: 'BOOTSTRAP_MISSING',
        severity: 'critical',
        title: 'diagnostics.bootstrapMissingTitle',
        description: 'diagnostics.bootstrapMissingDescription',
        affectedComponent: 'ConfigService',
        suggestedResolution: 'diagnostics.bootstrapMissingResolution'
      });
      return entries;
    }

    this.validateRequiredProperties(bootstrap, entries);
    this.validateUnknownWidgetTypes(bootstrap, manifest, entries);
    this.validateWidgetSettingsSchema(bootstrap, manifest, entries);
    this.validateDuplicateIds(bootstrap, entries);
    this.validateLayouts(bootstrap, entries);
    this.validateFeatureFlags(bootstrap, entries);
    this.validatePages(bootstrap, entries);
    this.validateNavigationTargets(bootstrap, entries, availableRoutes);
    this.validateMissingTranslations(bootstrap, entries, translate);
    this.validateMissingMedia(bootstrap, entries);

    return entries;
  }

  private validateRequiredProperties(bootstrap: BootstrapConfig, entries: DiagnosticEntry[]): void {
    const requiredPaths: Array<[string, unknown]> = [
      ['schemaVersion', bootstrap.schemaVersion],
      ['tenant.id', bootstrap.tenant?.id],
      ['tenant.slug', bootstrap.tenant?.slug],
      ['theme.themeId', bootstrap.theme?.themeId],
      ['branding.logoUrl', bootstrap.branding?.logoUrl],
      ['navigation.header', bootstrap.navigation?.header],
      ['pages', bootstrap.pages],
    ];

    for (const [path, value] of requiredPaths) {
      const missing = value == null || (Array.isArray(value) && value.length === 0) || (typeof value === 'string' && value.trim().length === 0);
      if (missing) {
        entries.push({
          code: 'BOOTSTRAP_REQUIRED_PROPERTY_MISSING',
          severity: 'error',
          title: 'diagnostics.requiredPropertyMissingTitle',
          description: `diagnostics.requiredPropertyMissingDescription:${path}`,
          affectedComponent: 'BootstrapConfig',
          suggestedResolution: 'diagnostics.requiredPropertyMissingResolution'
        });
      }
    }
  }

  private validateUnknownWidgetTypes(bootstrap: BootstrapConfig, manifest: WidgetManifestFile | null, entries: DiagnosticEntry[]): void {
    const known = new Set((manifest?.widgets ?? []).map(widget => widget.type));
    for (const page of bootstrap.pages ?? []) {
      for (const section of page.sections ?? []) {
        for (const widget of section.widgets ?? []) {
          if (known.size > 0 && !known.has(widget.type)) {
            entries.push({
              code: 'BOOTSTRAP_UNKNOWN_WIDGET_TYPE',
              severity: 'error',
              title: 'diagnostics.unknownWidgetTypeTitle',
              description: `diagnostics.unknownWidgetTypeDescription:${widget.type}`,
              affectedComponent: `page:${page.key}/section:${section.id}`,
              suggestedResolution: 'diagnostics.unknownWidgetTypeResolution'
            });
          }
        }
      }
    }
  }

  /**
   * Reuses the same shallow schema check as ProjectValidator.widgetSettingsSchemaIssues
   * (`validateAgainstSchemaLite`) so the editor and the diagnostics page never
   * disagree about what "valid widget settings" means - one check, two surfaces.
   */
  private validateWidgetSettingsSchema(bootstrap: BootstrapConfig, manifest: WidgetManifestFile | null, entries: DiagnosticEntry[]): void {
    const manifestByType = new Map((manifest?.widgets ?? []).map(widget => [widget.type, widget]));
    for (const page of bootstrap.pages ?? []) {
      for (const section of page.sections ?? []) {
        for (const widget of section.widgets ?? []) {
          const entry = manifestByType.get(widget.type);
          if (!entry?.settingsSchema || !widget.props || typeof widget.props !== 'object') {
            continue;
          }
          const errors = validateAgainstSchemaLite(widget.props, entry.settingsSchema);
          if (errors.length > 0) {
            entries.push({
              code: 'BOOTSTRAP_WIDGET_SETTINGS_SCHEMA_MISMATCH',
              severity: 'warning',
              title: 'diagnostics.widgetSettingsSchemaMismatchTitle',
              description: `diagnostics.widgetSettingsSchemaMismatchDescription:${widget.type}(${errors.join(', ')})`,
              affectedComponent: `page:${page.key}/section:${section.id}/widget:${widget.id}`,
              suggestedResolution: 'diagnostics.widgetSettingsSchemaMismatchResolution'
            });
          }
        }
      }
    }
  }

  private validateDuplicateIds(bootstrap: BootstrapConfig, entries: DiagnosticEntry[]): void {
    const pageIds = new Set<string>();

    for (const page of bootstrap.pages ?? []) {
      if (pageIds.has(page.id)) {
        entries.push({
          code: 'BOOTSTRAP_DUPLICATE_PAGE_ID',
          severity: 'error',
          title: 'diagnostics.duplicateIdTitle',
          description: `diagnostics.duplicatePageIdDescription:${page.id}`,
          affectedComponent: `page:${page.key}`,
          suggestedResolution: 'diagnostics.duplicateIdResolution'
        });
      }
      pageIds.add(page.id);

      const sectionIds = new Set<string>();
      for (const section of page.sections ?? []) {
        if (sectionIds.has(section.id)) {
          entries.push({
            code: 'BOOTSTRAP_DUPLICATE_SECTION_ID',
            severity: 'error',
            title: 'diagnostics.duplicateIdTitle',
            description: `diagnostics.duplicateSectionIdDescription:${section.id}`,
            affectedComponent: `page:${page.key}`,
            suggestedResolution: 'diagnostics.duplicateIdResolution'
          });
        }
        sectionIds.add(section.id);

        const widgetIds = new Set<string>();
        for (const widget of section.widgets ?? []) {
          if (widgetIds.has(widget.id)) {
            entries.push({
              code: 'BOOTSTRAP_DUPLICATE_WIDGET_ID',
              severity: 'error',
              title: 'diagnostics.duplicateIdTitle',
              description: `diagnostics.duplicateWidgetIdDescription:${widget.id}`,
              affectedComponent: `page:${page.key}/section:${section.id}`,
              suggestedResolution: 'diagnostics.duplicateIdResolution'
            });
          }
          widgetIds.add(widget.id);
        }
      }
    }
  }

  private validateLayouts(bootstrap: BootstrapConfig, entries: DiagnosticEntry[]): void {
    for (const page of bootstrap.pages ?? []) {
      const layout = typeof page.layout === 'string' ? page.layout : page.layout?.type;
      if (!layout || !KNOWN_LAYOUTS.has(layout)) {
        entries.push({
          code: 'BOOTSTRAP_UNKNOWN_LAYOUT',
          severity: 'warning',
          title: 'diagnostics.unknownLayoutTitle',
          description: `diagnostics.unknownLayoutDescription:${layout ?? 'undefined'}`,
          affectedComponent: `page:${page.key}`,
          suggestedResolution: 'diagnostics.unknownLayoutResolution'
        });
      }
    }
  }

  private validateFeatureFlags(bootstrap: BootstrapConfig, entries: DiagnosticEntry[]): void {
    const featureFlags = bootstrap.featureFlags ?? {};
    for (const [key, value] of Object.entries(featureFlags)) {
      if (typeof value !== 'boolean') {
        entries.push({
          code: 'BOOTSTRAP_INVALID_FEATURE_FLAG',
          severity: 'error',
          title: 'diagnostics.invalidFeatureFlagTitle',
          description: `diagnostics.invalidFeatureFlagDescription:${key}`,
          affectedComponent: 'featureFlags',
          suggestedResolution: 'diagnostics.invalidFeatureFlagResolution'
        });
      }
    }
  }

  private validatePages(bootstrap: BootstrapConfig, entries: DiagnosticEntry[]): void {
    for (const page of bootstrap.pages ?? []) {
      const broken = !page.key || !page.title || !page.route?.path || !Array.isArray(page.sections);
      if (broken) {
        entries.push({
          code: 'BOOTSTRAP_BROKEN_PAGE_DEFINITION',
          severity: 'error',
          title: 'diagnostics.brokenPageDefinitionTitle',
          description: `diagnostics.brokenPageDefinitionDescription:${page.id}`,
          affectedComponent: `page:${page.id}`,
          suggestedResolution: 'diagnostics.brokenPageDefinitionResolution'
        });
      }
    }
  }

  private validateNavigationTargets(bootstrap: BootstrapConfig, entries: DiagnosticEntry[], availableRoutes: string[]): void {
    const allowed = new Set(availableRoutes);

    const validateItem = (route: string | undefined, location: string) => {
      if (!route) {
        return;
      }

      const normalized = route.startsWith('/') ? route : `/${route}`;
      if (!allowed.has(normalized)) {
        entries.push({
          code: 'BOOTSTRAP_INVALID_NAVIGATION_TARGET',
          severity: 'warning',
          title: 'diagnostics.invalidNavigationTargetTitle',
          description: `diagnostics.invalidNavigationTargetDescription:${normalized}`,
          affectedComponent: location,
          suggestedResolution: 'diagnostics.invalidNavigationTargetResolution'
        });
      }
    };

    for (const item of bootstrap.navigation?.header ?? []) {
      validateItem(item.route, `navigation.header:${item.id}`);
      for (const child of item.children ?? []) {
        validateItem(child.route, `navigation.header:${item.id}/${child.id}`);
      }
    }

    for (const item of bootstrap.navigation?.footer ?? []) {
      if ('items' in item) {
        for (const child of item.items ?? []) {
          validateItem(child.route, `navigation.footer.group`);
        }
      } else {
        validateItem(item.route, `navigation.footer:${item.id}`);
      }
    }
  }

  private validateMissingTranslations(bootstrap: BootstrapConfig, entries: DiagnosticEntry[], translate: TranslateService): void {
    for (const item of bootstrap.navigation?.header ?? []) {
      if (item.labelKey && translate.t(item.labelKey) === item.labelKey) {
        entries.push({
          code: 'BOOTSTRAP_MISSING_TRANSLATION',
          severity: 'warning',
          title: 'diagnostics.missingTranslationTitle',
          description: `diagnostics.missingTranslationDescription:${item.labelKey}`,
          affectedComponent: `navigation.header:${item.id}`,
          suggestedResolution: 'diagnostics.missingTranslationResolution'
        });
      }
    }
  }

  private validateMissingMedia(bootstrap: BootstrapConfig, entries: DiagnosticEntry[]): void {
    if (!bootstrap.branding?.logoUrl) {
      entries.push({
        code: 'BOOTSTRAP_MISSING_MEDIA',
        severity: 'warning',
        title: 'diagnostics.missingMediaTitle',
        description: 'diagnostics.missingMediaDescription:branding.logoUrl',
        affectedComponent: 'branding',
        suggestedResolution: 'diagnostics.missingMediaResolution'
      });
    }

    if (!bootstrap.branding?.faviconUrl) {
      entries.push({
        code: 'BOOTSTRAP_MISSING_MEDIA',
        severity: 'warning',
        title: 'diagnostics.missingMediaTitle',
        description: 'diagnostics.missingMediaDescription:branding.faviconUrl',
        affectedComponent: 'branding',
        suggestedResolution: 'diagnostics.missingMediaResolution'
      });
    }
  }
}
