import { DOCUMENT } from '@angular/common';
import { Inject } from '@angular/core';
import { Router } from '@angular/router';
import { environment } from '../../../../environments/environment';
import { RuntimeProviderStrategyService } from '../../../core/providers/runtime-provider-strategy.service';
import { PlatformRuntimeStateService } from '../../../core/runtime/platform-runtime-state.service';
import { RuntimeDiagnosticsService } from '../../../core/runtime/runtime-diagnostics.service';
import { BootstrapConfig } from '../../../shared/models/config';
import { WidgetManifestFile } from '../../../widgets/contracts/widget-manifest.contract';
import { DiagnosticEntry } from '../models/diagnostics.model';

export class RuntimeDiagnosticsValidator {
  constructor(
    private readonly runtimeState: PlatformRuntimeStateService,
    private readonly runtimeDiagnostics: RuntimeDiagnosticsService,
    private readonly strategy: RuntimeProviderStrategyService,
    private readonly router: Router,
    @Inject(DOCUMENT) private readonly document: Document
  ) {}

  validate(bootstrap: BootstrapConfig | null, manifest: WidgetManifestFile | null): DiagnosticEntry[] {
    const entries: DiagnosticEntry[] = [];

    if (!this.runtimeState.initialized()) {
      entries.push({
        code: 'RUNTIME_NOT_INITIALIZED',
        severity: 'critical',
        title: 'diagnostics.runtimeNotInitializedTitle',
        description: 'diagnostics.runtimeNotInitializedDescription',
        affectedComponent: 'PlatformRuntimeService',
        suggestedResolution: 'diagnostics.runtimeNotInitializedResolution'
      });
    }

    this.validateConfigFallbackUsage(entries);
    this.validateDatasourceCoverage(bootstrap, manifest, entries);
    this.validateWidgetFailures(entries);
    this.validateBrokenRoutes(entries);
    this.validateImageFailures(entries);
    this.validateMissingOptionalData(bootstrap, entries);

    return entries;
  }

  private validateConfigFallbackUsage(entries: DiagnosticEntry[]): void {
    const mode = this.strategy.getBootstrapProviderMode();
    if (mode === 'mock' && !environment.production) {
      entries.push({
        code: 'RUNTIME_FALLBACK_USAGE',
        severity: 'info',
        title: 'diagnostics.configFallbackUsageTitle',
        description: 'diagnostics.configFallbackUsageDescription',
        affectedComponent: 'RuntimeProviderStrategyService',
        suggestedResolution: 'diagnostics.configFallbackUsageResolution'
      });
    }
  }

  private validateDatasourceCoverage(bootstrap: BootstrapConfig | null, manifest: WidgetManifestFile | null, entries: DiagnosticEntry[]): void {
    if (!bootstrap || !manifest) {
      return;
    }

    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 definition = manifestByType.get(widget.type);
          if (!definition) {
            continue;
          }

          const requiresDataSource = definition.supportedDataSources.length > 0;
          const hasDataSource = typeof widget.props?.['source'] === 'string' || typeof definition.defaultSettings?.['source'] === 'string';

          if (requiresDataSource && !hasDataSource) {
            entries.push({
              code: 'RUNTIME_MISSING_DATASOURCE',
              severity: 'warning',
              title: 'diagnostics.missingDatasourceTitle',
              description: `diagnostics.missingDatasourceDescription:${widget.id}`,
              affectedComponent: `page:${page.key}/section:${section.id}`,
              suggestedResolution: 'diagnostics.missingDatasourceResolution'
            });
          }
        }
      }
    }
  }

  private validateWidgetFailures(entries: DiagnosticEntry[]): void {
    for (const event of this.runtimeDiagnostics.getUnknownWidgetEvents()) {
      entries.push({
        code: 'RUNTIME_WIDGET_RENDER_FAILURE',
        severity: 'error',
        title: 'diagnostics.widgetRenderFailureTitle',
        description: `diagnostics.widgetRenderFailureDescription:${event.widget}`,
        affectedComponent: `page:${event.page}/section:${event.section}`,
        suggestedResolution: 'diagnostics.widgetRenderFailureResolution'
      });
    }
  }

  private validateBrokenRoutes(entries: DiagnosticEntry[]): void {
    const routePaths = this.router.config
      .flatMap(route => route.children?.length ? route.children : [route])
      .map(route => route.path)
      .filter((path): path is string => typeof path === 'string');

    if (!routePaths.includes('search')) {
      entries.push({
        code: 'RUNTIME_BROKEN_ROUTE',
        severity: 'error',
        title: 'diagnostics.brokenRouteTitle',
        description: 'diagnostics.brokenRouteDescription:/search',
        affectedComponent: 'Router',
        suggestedResolution: 'diagnostics.brokenRouteResolution'
      });
    }
  }

  private validateImageFailures(entries: DiagnosticEntry[]): void {
    const failedImages = Array.from(this.document.images).filter(image => image.complete && image.naturalWidth === 0);
    for (const image of failedImages.slice(0, 10)) {
      entries.push({
        code: 'RUNTIME_IMAGE_LOAD_FAILED',
        severity: 'warning',
        title: 'diagnostics.imageLoadFailedTitle',
        description: `diagnostics.imageLoadFailedDescription:${image.currentSrc || image.src}`,
        affectedComponent: 'DOM',
        suggestedResolution: 'diagnostics.imageLoadFailedResolution'
      });
    }
  }

  private validateMissingOptionalData(bootstrap: BootstrapConfig | null, entries: DiagnosticEntry[]): void {
    if (!bootstrap) {
      return;
    }

    if (!bootstrap.branding?.supportEmail) {
      entries.push({
        code: 'RUNTIME_OPTIONAL_DATA_MISSING',
        severity: 'info',
        title: 'diagnostics.optionalDataMissingTitle',
        description: 'diagnostics.optionalDataMissingDescription:branding.supportEmail',
        affectedComponent: 'branding',
        suggestedResolution: 'diagnostics.optionalDataMissingResolution'
      });
    }

    if (!bootstrap.branding?.logoCompactUrl) {
      entries.push({
        code: 'RUNTIME_OPTIONAL_DATA_MISSING',
        severity: 'info',
        title: 'diagnostics.optionalDataMissingTitle',
        description: 'diagnostics.optionalDataMissingDescription:branding.logoCompactUrl',
        affectedComponent: 'branding',
        suggestedResolution: 'diagnostics.optionalDataMissingResolution'
      });
    }
  }
}
