import { AnalyticsSnapshot } from '@core/analytics/domain/entities/AnalyticsSnapshot';
import type { AnalyticsMetrics, SnapshotEntityType, SnapshotPeriod } from '@core/analytics/domain/types/AnalyticsSnapshot';

import { TypeOrmAnalyticsSchemaError } from '../errors/TypeOrmAnalyticsSchemaError';
import { AnalyticsSnapshotOrmEntity } from '../entities/AnalyticsSnapshotOrmEntity';
import { assertDate, assertEnumValue, assertNonEmptyString, assertNumber, assertRecord } from '../schema/TypeOrmAnalyticsSchemaGuards';

const VALID_ENTITY_TYPES: readonly SnapshotEntityType[] = ['league', 'driver', 'team', 'race', 'sponsor'] as const;
const VALID_PERIODS: readonly SnapshotPeriod[] = ['daily', 'weekly', 'monthly'] as const;

function assertMetrics(entityName: string, fieldName: string, value: unknown): asserts value is AnalyticsMetrics {
  assertRecord(entityName, fieldName, value);

  const metrics = value as Record<string, unknown>;

  assertNumber(entityName, `${fieldName}.pageViews`, metrics.pageViews);
  assertNumber(entityName, `${fieldName}.uniqueVisitors`, metrics.uniqueVisitors);
  assertNumber(entityName, `${fieldName}.avgSessionDuration`, metrics.avgSessionDuration);
  assertNumber(entityName, `${fieldName}.bounceRate`, metrics.bounceRate);
  assertNumber(entityName, `${fieldName}.engagementScore`, metrics.engagementScore);
  assertNumber(entityName, `${fieldName}.sponsorClicks`, metrics.sponsorClicks);
  assertNumber(entityName, `${fieldName}.sponsorUrlClicks`, metrics.sponsorUrlClicks);
  assertNumber(entityName, `${fieldName}.socialShares`, metrics.socialShares);
  assertNumber(entityName, `${fieldName}.leagueJoins`, metrics.leagueJoins);
  assertNumber(entityName, `${fieldName}.raceRegistrations`, metrics.raceRegistrations);
  assertNumber(entityName, `${fieldName}.exposureValue`, metrics.exposureValue);
}

export class AnalyticsSnapshotOrmMapper {
  toOrmEntity(domain: AnalyticsSnapshot): AnalyticsSnapshotOrmEntity {
    const entity = new AnalyticsSnapshotOrmEntity();
    entity.id = domain.id;
    entity.entityType = domain.entityType;
    entity.entityId = domain.entityId;
    entity.period = domain.period;
    entity.startDate = domain.startDate;
    entity.endDate = domain.endDate;
    entity.metrics = domain.metrics;
    entity.createdAt = domain.createdAt;
    return entity;
  }

  toDomain(entity: AnalyticsSnapshotOrmEntity): AnalyticsSnapshot {
    const entityName = 'AnalyticsSnapshot';

    try {
      assertNonEmptyString(entityName, 'id', entity.id);
      assertEnumValue<SnapshotEntityType>(entityName, 'entityType', entity.entityType, VALID_ENTITY_TYPES);
      assertNonEmptyString(entityName, 'entityId', entity.entityId);
      assertEnumValue<SnapshotPeriod>(entityName, 'period', entity.period, VALID_PERIODS);

      assertDate(entityName, 'startDate', entity.startDate);
      assertDate(entityName, 'endDate', entity.endDate);

      assertMetrics(entityName, 'metrics', entity.metrics);

      assertDate(entityName, 'createdAt', entity.createdAt);

      return AnalyticsSnapshot.create({
        id: entity.id,
        entityType: entity.entityType,
        entityId: entity.entityId,
        period: entity.period,
        startDate: entity.startDate,
        endDate: entity.endDate,
        metrics: entity.metrics,
        createdAt: entity.createdAt,
      });
    } catch (error) {
      if (error instanceof TypeOrmAnalyticsSchemaError) {
        throw error;
      }

      const message = error instanceof Error ? error.message : 'Invalid persisted AnalyticsSnapshot';
      throw new TypeOrmAnalyticsSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });
    }
  }
}