import { DOCUMENT } from '@angular/common';
import { Injectable, computed, inject } from '@angular/core';
import { Router } from '@angular/router';
import { forkJoin, map, of } from 'rxjs';
import { environment } from '../../../../environments/environment';
import { ConfigService } from '../../../core/config/config.service';
import { TenantResolverService } from '../../../core/config/tenant-resolver.service';
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 { TranslateService } from '../../../i18n/translate.service';
import { WidgetManifestService } from '../../../widgets/registry/widget-manifest.service';
import { WidgetRegistryService } from '../../../widgets/registry/widget-registry.service';
import { DiagnosticsReport } from '../models/diagnostics.model';
import { DiagnosticsLoggerService } from '../services/diagnostics-logger.service';
import { BootstrapDiagnosticsValidator } from '../validators/bootstrap-diagnostics.validator';
import { calculateHealthScore } from '../validators/diagnostics-health-score.util';
import { RuntimeDiagnosticsValidator } from '../validators/runtime-diagnostics.validator';

@Injectable({ providedIn: 'root' })
export class DiagnosticsFacade {
  private readonly configService = inject(ConfigService);
  private readonly tenantResolver = inject(TenantResolverService);
  private readonly runtimeState = inject(PlatformRuntimeStateService);
  private readonly runtimeDiagnostics = inject(RuntimeDiagnosticsService);
  private readonly translate = inject(TranslateService);
  private readonly widgetManifest = inject(WidgetManifestService);
  private readonly widgetRegistry = inject(WidgetRegistryService);
  private readonly router = inject(Router);
  private readonly strategy = inject(RuntimeProviderStrategyService);
  private readonly logger = inject(DiagnosticsLoggerService);
  private readonly document = inject(DOCUMENT);

  readonly devMode = !environment.production;
  readonly logs = this.logger.logs;
  readonly availableRoutes = computed(() => this.collectAvailableRoutes());

  loadReport() {
    const bootstrapValidator = new BootstrapDiagnosticsValidator();
    const runtimeValidator = new RuntimeDiagnosticsValidator(
      this.runtimeState,
      this.runtimeDiagnostics,
      this.strategy,
      this.router,
      this.document
    );

    return forkJoin({
      bootstrap: this.configService.loadBootstrap().pipe(map(value => value), map(value => value)),
      manifest: this.widgetManifest.getManifest().pipe(map(value => value)),
    }).pipe(
      map(({ bootstrap, manifest }) => {
        const entries = [
          ...bootstrapValidator.validate(bootstrap, manifest, this.collectAvailableRoutes(), this.translate),
          ...runtimeValidator.validate(bootstrap, manifest),
        ];

        for (const entry of entries) {
          this.logger.log(entry);
        }

        const checks = [
          { key: 'bootstrapLoaded', passed: !!bootstrap, severity: 'critical' as const },
          { key: 'tenantResolved', passed: this.tenantResolver.getTenantKey().trim().length > 0, severity: 'error' as const },
          { key: 'runtimeInitialized', passed: this.runtimeState.initialized(), severity: 'critical' as const },
          { key: 'themeLoaded', passed: !!bootstrap?.theme?.themeId && this.document.documentElement.getAttribute('data-theme-id')?.length! > 0, severity: 'warning' as const },
          { key: 'widgetManifestLoaded', passed: (manifest?.widgets?.length ?? 0) > 0, severity: 'warning' as const },
          { key: 'sectionEngineInitialized', passed: true, severity: 'info' as const },
          { key: 'configurationEngineInitialized', passed: !!this.configService.getBootstrapSnapshot(), severity: 'error' as const },
          { key: 'translationResourcesAvailable', passed: this.translate.t('app.pageTitle') !== 'app.pageTitle', severity: 'warning' as const },
          { key: 'requiredAssetsAvailable', passed: Array.from(this.document.images).every(image => !image.complete || image.naturalWidth > 0), severity: 'warning' as const },
        ];

        const summary = {
          score: calculateHealthScore(entries),
          passedChecks: checks.filter(check => check.passed).length,
          infoCount: entries.filter(entry => entry.severity === 'info').length,
          warningCount: entries.filter(entry => entry.severity === 'warning').length,
          errorCount: entries.filter(entry => entry.severity === 'error').length,
          criticalCount: entries.filter(entry => entry.severity === 'critical').length,
        };

        return {
          generatedAt: new Date().toISOString(),
          summary,
          checks,
          entries,
        } satisfies DiagnosticsReport;
      })
    );
  }

  private collectAvailableRoutes(): string[] {
    const visit = (routes: any[], prefix = ''): string[] => routes.flatMap(route => {
      const current = route.path ? `${prefix}/${route.path}`.replace(/\/+/g, '/').replace(/\/$/, '') || '/' : prefix || '/';
      const children = route.children ? visit(route.children, current === '/' ? '' : current) : [];
      return [current || '/', ...children];
    });

    return visit(this.router.config)
      .map(route => route.startsWith('/:lang') ? route.slice(6) || '/' : route)
      .map(route => route === '' ? '/' : route)
      .filter((route, index, source) => source.indexOf(route) === index);
  }
}
