import { HealthKitRepository, AuthorizationStatus, HealthKitTypeInfo, HealthKitRepositoryConfig } from '../../domain/repositories/HealthKitRepository';
import { HealthKitQuantitySample, HealthKitCategorySample, HealthKitWorkout } from '../../domain/entities/HealthKitSample';
import { HealthKitIdentifier, HealthKitUnit, DateRange } from '../../domain/value-objects/HealthKitIdentifier';
import { HealthKitDataSource } from '../datasources/HealthKitDataSource';
import { HealthKitMapper } from '../mappers/HealthKitMapper';

export class HealthKitRepositoryImpl implements HealthKitRepository {
  private readonly mapper: HealthKitMapper;
  private readonly config: HealthKitRepositoryConfig;

  constructor(
    private readonly dataSource: HealthKitDataSource,
    config: HealthKitRepositoryConfig = {}
  ) {
    this.mapper = new HealthKitMapper();
    this.config = {
      defaultDays: 7,
      enableLogging: false,
      retryAttempts: 3,
      ...config
    };
  }

  async requestAuthorization(): Promise<boolean> {
    return await this.dataSource.requestAuthorization();
  }

  async requestSelectiveAuthorization(readTypes: HealthKitIdentifier[], writeTypes: HealthKitIdentifier[] = []): Promise<boolean> {
    const identifierStrings = [...readTypes, ...writeTypes].map(id => id.toString());
    return await this.dataSource.requestSelectiveAuthorization(
      readTypes.map(id => id.toString()),
      writeTypes.map(id => id.toString())
    );
  }

  async getAuthorizationStatus(identifiers: HealthKitIdentifier[]): Promise<AuthorizationStatus[]> {
    const identifierStrings = identifiers.map(id => id.toString());
    return await this.dataSource.getAuthorizationStatus(identifierStrings);
  }

  async getQuantitySamplesWithRange(identifier: HealthKitIdentifier, unit: string, startDate: number, endDate: number): Promise<number[]> {
    return await this.dataSource.getQuantitySamplesWithRange(identifier.toString(), unit, startDate, endDate);
  }

  async getCategorySamplesWithRange(identifier: HealthKitIdentifier, startDate: number, endDate: number): Promise<HealthKitCategorySample[]> {
    const rawData = await this.dataSource.getCategorySamplesWithRange(identifier.toString(), startDate, endDate);
    return rawData.map(item => this.mapper.toCategorySample(item));
  }

  async getWorkoutsWithRange(startDate: number, endDate: number): Promise<HealthKitWorkout[]> {
    const rawData = await this.dataSource.getWorkoutsWithRange(startDate, endDate);
    return rawData.map(item => this.mapper.toWorkout(item));
  }

  async getQuantitySamples(identifier: HealthKitIdentifier, unit: HealthKitUnit): Promise<HealthKitQuantitySample[]> {
    const rawData = await this.dataSource.getQuantitySamplesForDays(identifier.toString(), unit.toString(), 7);
    return rawData.map(item => this.mapper.toQuantitySample(item));
  }

  async getCategorySamples(identifier: HealthKitIdentifier): Promise<HealthKitCategorySample[]> {
    const rawData = await this.dataSource.getCategorySamplesForDays(identifier.toString(), 7);
    return rawData.map(item => this.mapper.toCategorySample(item));
  }

  async getWorkouts(): Promise<HealthKitWorkout[]> {
    const rawData = await this.dataSource.getWorkoutsForDays(7);
    return rawData.map(item => this.mapper.toWorkout(item));
  }

  async getQuantitySamplesForDays(
    identifier: HealthKitIdentifier,
    unit: HealthKitUnit,
    days: number
  ): Promise<HealthKitQuantitySample[]> {
    const rawData = await this.dataSource.getQuantitySamplesForDays(
      identifier.toString(),
      unit.toString(),
      days
    );

    return rawData.map(item => this.mapper.toQuantitySample(item));
  }

  async getCategorySamplesForDays(
    identifier: HealthKitIdentifier,
    days: number
  ): Promise<HealthKitCategorySample[]> {
    const rawData = await this.dataSource.getCategorySamplesForDays(
      identifier.toString(),
      days
    );

    return rawData.map(item => this.mapper.toCategorySample(item));
  }

  async getWorkoutsForDays(days: number): Promise<HealthKitWorkout[]> {
    const rawData = await this.dataSource.getWorkoutsForDays(days);
    return rawData.map(item => this.mapper.toWorkout(item));
  }

  isAvailable(): boolean {
    return this.dataSource.isAvailable();
  }

  private formatDate(date: Date): string {
    return date.toISOString();
  }
} 