import { Injectable, computed, effect, inject, signal } from '@angular/core';
import { take } from 'rxjs/operators';
import { ProjectEditorFacade } from '../../../project-editor/facade/project-editor.facade';
import { EditorSchemaService } from '../../../project-editor/schema/editor-schema.service';
import { AdminAuthService } from '@marketplaces/auth';
import { environment } from '../../../../../environments/environment';
import { ADMIN_DASHBOARD_METRICS_GATEWAY } from '../services/admin-dashboard-metrics-gateway.token';
import { AdminDashboardHistoryService } from '../services/admin-dashboard-history.service';
import {
  AdminDashboardCardState,
  AdminDashboardHealthCheck,
  AdminDashboardHomeHealthCheck,
  AdminDashboardMetrics,
  AdminDashboardQuickAction,
  AdminDashboardShortcut,
} from '../models/admin-dashboard.model';

const QUICK_ACTIONS: AdminDashboardQuickAction[] = [
  { id: 'add-product', icon: 'plusCircle', labelKey: 'dashboard.actionAddProduct', descriptionKey: 'dashboard.actionAddProductDescription', route: ['backoffice', 'products', 'create'] },
  { id: 'create-category', icon: 'network', labelKey: 'dashboard.actionCreateCategory', descriptionKey: 'dashboard.actionCreateCategoryDescription', route: ['backoffice', 'categories', 'create'] },
  { id: 'edit-project', icon: 'layoutGrid', labelKey: 'dashboard.actionEditProject', descriptionKey: 'dashboard.actionEditProjectDescription', route: ['edit'] },
  { id: 'edit-homepage', icon: 'home', labelKey: 'dashboard.actionEditHomepage', descriptionKey: 'dashboard.actionEditHomepageDescription', route: ['edit', 'homepage'] },
  { id: 'media-library', icon: 'images', labelKey: 'dashboard.actionMediaLibrary', descriptionKey: 'dashboard.actionMediaLibraryDescription', route: ['backoffice', 'media'] },
  { id: 'orders', icon: 'cart', labelKey: 'dashboard.actionOrders', descriptionKey: 'dashboard.actionOrdersDescription', route: ['backoffice', 'orders'] },
];

const SHORTCUTS: AdminDashboardShortcut[] = [
  { id: 'products', icon: 'package', labelKey: 'dashboard.actionProducts', route: ['backoffice', 'products'] },
  { id: 'categories', icon: 'tags', labelKey: 'dashboard.actionCategories', route: ['backoffice', 'categories'] },
  { id: 'marketplace-builder', icon: 'network', labelKey: 'dashboard.shortcutMarketplaceBuilder', route: ['edit'] },
  { id: 'static-pages', icon: 'edit', labelKey: 'dashboard.actionStaticPages', route: ['backoffice', 'static-pages'] },
  { id: 'orders', icon: 'cart', labelKey: 'dashboard.actionOrders', route: ['backoffice', 'orders'] },
  { id: 'users', icon: 'users', labelKey: 'dashboard.actionUsers', route: ['backoffice', 'users'] },
  { id: 'settings', icon: 'settings', labelKey: 'dashboard.shortcutSettings', route: ['backoffice', 'settings'] },
  { id: 'media-library', icon: 'images', labelKey: 'dashboard.actionMediaLibrary', route: ['backoffice', 'media'] },
  { id: 'content', icon: 'alignLeft', labelKey: 'dashboard.shortcutContent', route: ['edit', 'static-pages'] },
];

/**
 * Composes ProjectEditorFacade (bootstrap/status/save-publish timestamps/validation/dirty
 * state) with dashboard-only metrics/history/auth so the page component stays presentational.
 * Cards read through here, never directly from ConfigService or localStorage - swapping local
 * sources for real backend endpoints only touches this facade and the gateways it calls, per
 * ADR-006/007.
 */
@Injectable({ providedIn: 'root' })
export class AdminDashboardFacade {
  private readonly projectEditor = inject(ProjectEditorFacade);
  private readonly schema = inject(EditorSchemaService);
  private readonly adminAuth = inject(AdminAuthService);
  private readonly metricsGateway = inject(ADMIN_DASHBOARD_METRICS_GATEWAY);
  private readonly history = inject(AdminDashboardHistoryService);

  private readonly metricsState = signal<AdminDashboardCardState<AdminDashboardMetrics>>({ status: 'loading', value: null });
  private readonly activityTick = signal(0);

  readonly bootstrap = this.projectEditor.bootstrap;
  readonly status = this.projectEditor.status;
  readonly dirty = this.projectEditor.dirty;
  readonly lastSavedAt = this.projectEditor.lastSavedAt;
  readonly lastPublishedAt = this.projectEditor.lastPublishedAt;
  readonly validationIssues = this.projectEditor.validationIssues;
  readonly homepageWidgets = this.projectEditor.homepageWidgets;
  readonly modifiedFields = this.projectEditor.modifiedFields;
  readonly metrics = this.metricsState.asReadonly();

  private static readonly MAX_MODIFIED_FIELD_CHIPS = 6;

  /** Human field labels (schema labelKey) for the fields the draft actually changed, capped so the widget stays scannable. */
  readonly modifiedFieldLabelKeys = computed<string[]>(() => {
    const keys = [...this.modifiedFields()];
    const fields = this.schema.all();
    return keys
      .slice(0, AdminDashboardFacade.MAX_MODIFIED_FIELD_CHIPS)
      .map(key => fields.find(field => field.key === key)?.labelKey ?? key);
  });

  readonly modifiedFieldsOverflowCount = computed(() =>
    Math.max(0, this.modifiedFields().size - AdminDashboardFacade.MAX_MODIFIED_FIELD_CHIPS),
  );

  readonly currentUserName = this.adminAuth.displayName;
  readonly isProductionEnvironment = environment.production;

  readonly quickActions: AdminDashboardQuickAction[] = QUICK_ACTIONS;
  readonly shortcuts: AdminDashboardShortcut[] = SHORTCUTS;

  readonly enabledWidgetsCount = computed(() => this.homepageWidgets().length);

  readonly staticPagesUnpublishedCount = computed(() => {
    const staticPages = this.bootstrap()?.staticPages;
    if (!staticPages) {
      return 0;
    }
    const pages = Array.isArray(staticPages) ? staticPages : Object.values(staticPages);
    return pages.filter(page => (page as { status?: string }).status !== 'published').length;
  });

  readonly activityEntries = computed(() => {
    this.activityTick();
    const tenantId = this.bootstrap()?.tenant.id;
    return tenantId ? this.history.list(tenantId) : [];
  });

  /** Unchanged shape/logic - AdminMonitoringPageComponent also consumes this signal. */
  readonly healthChecks = computed<AdminDashboardHealthCheck[]>(() => {
    const current = this.bootstrap();
    const issues = new Set(this.validationIssues().map(issue => issue.code));
    return [
      { code: 'bootstrap-valid', labelKey: 'dashboard.healthBootstrapValid', healthy: !!current?.schemaVersion },
      { code: 'configuration-valid', labelKey: 'dashboard.healthConfigurationValid', healthy: issues.size === 0 },
      { code: 'missing-translations', labelKey: 'dashboard.healthMissingTranslations', healthy: !issues.has('missing-translations') },
      { code: 'invalid-colors', labelKey: 'dashboard.healthInvalidColors', healthy: !issues.has('invalid-colors') },
      { code: 'invalid-widget-references', labelKey: 'dashboard.healthInvalidWidgetReferences', healthy: !issues.has('missing-widget') },
      { code: 'invalid-layouts', labelKey: 'dashboard.healthInvalidLayouts', healthy: !issues.has('invalid-layouts') },
    ];
  });

  readonly homeHealthChecks = computed<AdminDashboardHomeHealthCheck[]>(() => {
    const current = this.bootstrap();
    const bootstrapLoading = !current;
    const issues = new Set(this.validationIssues().map(issue => issue.code));
    const metrics = this.metrics();
    const staticPagesUnpublished = this.staticPagesUnpublishedCount();

    return [
      { code: 'configuration-valid', labelKey: 'dashboard.healthConfigurationValid', status: bootstrapLoading ? 'loading' : issues.size === 0 ? 'healthy' : 'unhealthy' },
      { code: 'products-count', labelKey: 'dashboard.healthProductsCount', status: metrics.status === 'loading' ? 'loading' : metrics.status === 'error' ? 'unhealthy' : 'healthy', displayValue: metrics.value ? String(metrics.value.productsCount) : null },
      { code: 'categories-count', labelKey: 'dashboard.healthCategoriesCount', status: metrics.status === 'loading' ? 'loading' : metrics.status === 'error' ? 'unhealthy' : 'healthy', displayValue: metrics.value ? String(metrics.value.categoriesCount) : null },
      // Per PHASE-9-TENANT-REGISTRY-DOMAINS-CONTRACT.md §7's target metric list.
      // No contract yet defines /api/admin/v2/dashboard/metrics's exact
      // response (FRONTEND-API-SURFACE-COMPLETE.md §15), so these fields are
      // optional on AdminDashboardMetrics - 'unknown' (not 'healthy') is the
      // correct status while the field is absent, same pattern as
      // 'images-without-alt' below: a successful fetch with no field present
      // is not the same as a metric that is confirmed healthy.
      { code: 'gmv', labelKey: 'dashboard.healthGmv', status: metrics.status === 'loading' ? 'loading' : metrics.value?.gmvMinor === undefined ? 'unknown' : 'healthy', displayValue: metrics.value?.gmvMinor !== undefined ? `${(metrics.value.gmvMinor / 100).toFixed(2)} ${metrics.value.currency ?? ''}`.trim() : null },
      { code: 'paid-orders', labelKey: 'dashboard.healthPaidOrders', status: metrics.status === 'loading' ? 'loading' : metrics.value?.paidOrdersCount === undefined ? 'unknown' : 'healthy', displayValue: metrics.value?.paidOrdersCount !== undefined ? String(metrics.value.paidOrdersCount) : null },
      { code: 'conversion-rate', labelKey: 'dashboard.healthConversionRate', status: metrics.status === 'loading' ? 'loading' : metrics.value?.conversionRate === undefined ? 'unknown' : 'healthy', displayValue: metrics.value?.conversionRate !== undefined ? `${(metrics.value.conversionRate * 100).toFixed(1)}%` : null },
      { code: 'payment-failure-rate', labelKey: 'dashboard.healthPaymentFailureRate', status: metrics.status === 'loading' ? 'loading' : metrics.value?.paymentFailureRate === undefined ? 'unknown' : metrics.value.paymentFailureRate > 0.05 ? 'attention' : 'healthy', displayValue: metrics.value?.paymentFailureRate !== undefined ? `${(metrics.value.paymentFailureRate * 100).toFixed(1)}%` : null },
      { code: 'moderation-queue', labelKey: 'dashboard.healthModerationQueue', status: metrics.status === 'loading' ? 'loading' : metrics.value?.moderationQueueCount === undefined ? 'unknown' : metrics.value.moderationQueueCount > 0 ? 'attention' : 'healthy', displayValue: metrics.value?.moderationQueueCount !== undefined ? String(metrics.value.moderationQueueCount) : null },
      { code: 'low-stock', labelKey: 'dashboard.healthLowStock', status: metrics.status === 'loading' ? 'loading' : metrics.value?.lowStockCount === undefined ? 'unknown' : metrics.value.lowStockCount > 0 ? 'attention' : 'healthy', displayValue: metrics.value?.lowStockCount !== undefined ? String(metrics.value.lowStockCount) : null },
      { code: 'unmatched-events', labelKey: 'dashboard.healthUnmatchedEvents', status: metrics.status === 'loading' ? 'loading' : metrics.value?.unmatchedEventsCount === undefined ? 'unknown' : metrics.value.unmatchedEventsCount > 0 ? 'attention' : 'healthy', displayValue: metrics.value?.unmatchedEventsCount !== undefined ? String(metrics.value.unmatchedEventsCount) : null },
      { code: 'integration-health', labelKey: 'dashboard.healthIntegrationHealth', status: metrics.status === 'loading' ? 'loading' : metrics.value?.integrationTotalCount === undefined ? 'unknown' : metrics.value.integrationHealthyCount === metrics.value.integrationTotalCount ? 'healthy' : 'attention', displayValue: metrics.value?.integrationTotalCount !== undefined ? `${metrics.value.integrationHealthyCount ?? 0}/${metrics.value.integrationTotalCount}` : null },
      { code: 'missing-translations', labelKey: 'dashboard.healthMissingTranslations', status: bootstrapLoading ? 'loading' : issues.has('missing-translations') ? 'unhealthy' : 'healthy' },
      { code: 'draft-exists', labelKey: 'dashboard.healthDraftExists', status: bootstrapLoading ? 'loading' : this.dirty() ? 'attention' : 'healthy' },
      { code: 'images-without-alt', labelKey: 'dashboard.healthImagesWithoutAlt', status: 'unknown' },
      { code: 'static-pages-unpublished', labelKey: 'dashboard.healthStaticPagesUnpublished', status: bootstrapLoading ? 'loading' : staticPagesUnpublished > 0 ? 'attention' : 'healthy', displayValue: bootstrapLoading ? null : String(staticPagesUnpublished) },
      { code: 'homepage-configured', labelKey: 'dashboard.healthHomepageConfigured', status: bootstrapLoading ? 'loading' : this.enabledWidgetsCount() > 0 ? 'healthy' : 'attention' },
      { code: 'theme-configured', labelKey: 'dashboard.healthThemeConfigured', status: bootstrapLoading ? 'loading' : current?.theme?.themeId ? 'healthy' : 'attention' },
    ];
  });

  private lastRecordedSavedAt: number | null = null;
  private lastRecordedPublishedAt: number | null = null;
  private historyPrimed = false;

  constructor() {
    effect(() => {
      const tenantId = this.bootstrap()?.tenant.id;
      const savedAt = this.lastSavedAt();
      const publishedAt = this.lastPublishedAt();
      if (!tenantId) {
        return;
      }

      if (!this.historyPrimed) {
        this.historyPrimed = true;
        this.lastRecordedSavedAt = savedAt;
        this.lastRecordedPublishedAt = publishedAt;
        return;
      }

      let recorded = false;
      if (savedAt !== null && savedAt !== this.lastRecordedSavedAt) {
        this.lastRecordedSavedAt = savedAt;
        this.history.record(tenantId, 'draft-saved', savedAt);
        recorded = true;
      }
      if (publishedAt !== null && publishedAt !== this.lastRecordedPublishedAt) {
        this.lastRecordedPublishedAt = publishedAt;
        this.history.record(tenantId, 'published', publishedAt);
        recorded = true;
      }
      if (recorded) {
        this.activityTick.update(tick => tick + 1);
      }
    });
  }

  ensureLoaded(): void {
    if (!this.bootstrap()) {
      this.projectEditor.loadBootstrap();
    }
    this.loadMetrics();
  }

  loadMetrics(): void {
    this.metricsState.set({ status: 'loading', value: null });
    this.metricsGateway.loadMetrics().pipe(take(1)).subscribe({
      next: metrics => this.metricsState.set({
        status: metrics.categoriesCount === 0 && metrics.productsCount === 0 ? 'empty' : 'ready',
        value: metrics,
      }),
      error: () => this.metricsState.set({ status: 'error', value: null }),
    });
  }

  publishDraft(): void {
    this.projectEditor.publish();
  }

  discardDraft(): void {
    this.projectEditor.resetDraft();
  }
}
