import { NativeModule, requireNativeModule } from "expo-modules-core";

export interface StepUpdateEvent {
  steps: number;
  date: string;
}

export interface BodyWeightSample {
  /** Body weight value expressed in kilograms */
  value: number;
  /** Epoch timestamp in milliseconds */
  time: number;
  /** ISO-8601 timestamp string */
  isoDate: string;
  /** Optional source of the measurement */
  source?: string;
}

export type BodyWeightUpdateEvent = BodyWeightSample;

export type SleepStageType =
  | "InBed"
  | "Awake"
  | "AsleepREM"
  | "AsleepCore"
  | "AsleepDeep"
  | "Sleeping"
  | "Light"
  | "Deep"
  | "REM"
  | "AwakeInBed"
  | "OutOfBed"
  | "Unknown";

export interface SleepStage {
  /** The type of sleep stage */
  type: SleepStageType;
  /** Start time in milliseconds since epoch */
  startTime: number;
  /** End time in milliseconds since epoch */
  endTime: number;
  /** Duration in milliseconds */
  duration: number;
}

export interface SleepSession {
  /** Start time of the sleep session in milliseconds since epoch */
  startTime: number;
  /** End time of the sleep session in milliseconds since epoch */
  endTime: number;
  /** Total duration in milliseconds */
  totalDuration: number;
  /** ISO-8601 timestamp string for start */
  isoStartDate: string;
  /** ISO-8601 timestamp string for end */
  isoEndDate: string;
  /** Array of sleep stages within this session */
  stages: SleepStage[];
  /** Optional source of the sleep data */
  source?: string;
}

export type SleepUpdateEvent = SleepSession;

export type HealthSubscription = {
  remove(): void;
};

export type HealthModuleEvents = {
  onStepDataUpdate: (event: StepUpdateEvent) => void;
  onBodyWeightDataUpdate: (event: BodyWeightUpdateEvent) => void;
  onSleepDataUpdate: (event: SleepUpdateEvent) => void;
};

export type UpdateFrequency = "immediate" | "hourly" | "daily" | "weekly";

/**
 * Snapshot describing the runtime state of the native health integration.
 * Returned by `getHealthDiagnostics()` — every field is best-effort and may be
 * `null`/empty if the underlying API call failed or the platform is iOS.
 */
export interface HealthDiagnostics {
  /** AVAILABLE | UNAVAILABLE | PROVIDER_UPDATE_REQUIRED | EXCEPTION | UNKNOWN */
  sdkStatus: string;
  providerPackage: string | null;
  providerVersionCode: number | null;
  providerVersionName: string | null;
  /** null on iOS — HealthKit doesn't expose read-auth state */
  permissionsGranted: boolean | null;
  grantedPermissions: string[];
  backgroundDeliveryEnabled: boolean;
  /** Epoch ms of the last WorkManager run, or null if it has never run */
  lastWorkerRunMs: number | null;
  lastWorkerResult: string | null;
  lastWorkerError: string | null;
  lastChangesTokenIssuedMs: number | null;
  /** WorkInfo state name: ENQUEUED | RUNNING | SUCCEEDED | FAILED | CANCELLED | BLOCKED */
  workManagerState: string | null;
  oemBrand: string | null;
  oemManufacturer: string | null;
  oemModel: string | null;
  oemDevice: string | null;
  osSdkInt: number | null;
  osRelease: string | null;
  ignoringBatteryOptimizations: boolean;
}

export interface OpenSettingsResult {
  ok: boolean;
  intentUsed: string | null;
}

export interface OpenOemSettingsResult extends OpenSettingsResult {
  oem: string;
}

export interface HealthModuleInterface {
  isHealthDataAvailable: boolean;
  checkHealthDataAvailable(): boolean;
  requestAuthorization(): Promise<boolean>;
  /**
   * Get the step count for a specific day
   * @param startDate - The start date in milliseconds since epoch
   * @param endDate - The end date in milliseconds since epoch
   */
  getStepCount(startDate: number, endDate: number): Promise<number>;
  /**
   * Check whether any step records exist for a given date range.
   * @param startDate - The start date in milliseconds since epoch
   * @param endDate - The end date in milliseconds since epoch
   */
  hasStepDataForDate(startDate: number, endDate: number): Promise<boolean>;
  /**
   * Enable background delivery for step count updates
   */
  enableBackgroundDelivery(frequency: UpdateFrequency): Promise<boolean>;
  /**
   * Disable background delivery for step count updates
   */
  disableBackgroundDelivery(): Promise<boolean>;
  /**
   * Enable body weight change notifications.
   */
  enableBodyWeightUpdates(frequency: UpdateFrequency): Promise<boolean>;
  /**
   * Disable body weight change notifications.
   */
  disableBodyWeightUpdates(): Promise<boolean>;
  /**
   * Fetch weight samples between two timestamps (inclusive) in chronological order.
   */
  getBodyWeightSamples(startDate: number, endDate: number): Promise<BodyWeightSample[]>;
  /**
   * Retrieve the most recent recorded body weight or null if none exist.
   */
  getLatestBodyWeight(): Promise<BodyWeightSample | null>;
  /**
   * Get sleep sessions for a specific date range
   * @param startDate - The start date in milliseconds since epoch
   * @param endDate - The end date in milliseconds since epoch
   */
  getSleepSessions(startDate: number, endDate: number): Promise<SleepSession[]>;
  /**
   * Enable sleep data change notifications.
   */
  enableSleepUpdates(frequency: UpdateFrequency): Promise<boolean>;
  /**
   * Disable sleep data change notifications.
   */
  disableSleepUpdates(): Promise<boolean>;
  /**
   * Returns a fresh diagnostic snapshot of the health integration. Used by the
   * step-tracking diagnostic screen and Sentry tag enricher. Never throws —
   * fields are populated best-effort.
   */
  getHealthDiagnostics(): Promise<HealthDiagnostics>;
  /**
   * Open the system Health Connect settings UI (Android). On failure, falls
   * back to the Play Store listing. iOS opens the Health app via Settings.
   */
  openHealthConnectSettings(): Promise<boolean>;
  /**
   * Open the OS battery-optimization settings for this app. Tries multiple
   * intents in order of specificity. iOS resolves to false (not applicable).
   */
  openBatteryOptimizationSettings(): Promise<OpenSettingsResult>;
  /**
   * Open the OEM-specific auto-launch / background-activity manager (ColorOS,
   * MIUI, EMUI, OnePlus, Vivo). Falls back to app details settings. The `oem`
   * field reports which family was detected.
   */
  openOemAppLaunchSettings(): Promise<OpenOemSettingsResult>;
  /**
   * Schedule an immediate WorkManager sync run for the Health Connect change
   * pipeline. Useful from the diagnostic screen "Run sync now" button.
   */
  triggerSyncNow(): Promise<boolean>;
}

declare class HealthModule
  extends NativeModule<HealthModuleEvents>
  implements HealthModuleInterface
{
  isHealthDataAvailable: boolean;
  checkHealthDataAvailable(): boolean;
  requestAuthorization(): Promise<boolean>;
  getStepCount(startDate: number, endDate: number): Promise<number>;
  hasStepDataForDate(startDate: number, endDate: number): Promise<boolean>;
  enableBackgroundDelivery(frequency: UpdateFrequency): Promise<boolean>;
  disableBackgroundDelivery(): Promise<boolean>;
  enableBodyWeightUpdates(frequency: UpdateFrequency): Promise<boolean>;
  disableBodyWeightUpdates(): Promise<boolean>;
  getBodyWeightSamples(startDate: number, endDate: number): Promise<BodyWeightSample[]>;
  getLatestBodyWeight(): Promise<BodyWeightSample | null>;
  getSleepSessions(startDate: number, endDate: number): Promise<SleepSession[]>;
  enableSleepUpdates(frequency: UpdateFrequency): Promise<boolean>;
  disableSleepUpdates(): Promise<boolean>;
  getHealthDiagnostics(): Promise<HealthDiagnostics>;
  openHealthConnectSettings(): Promise<boolean>;
  openBatteryOptimizationSettings(): Promise<OpenSettingsResult>;
  openOemAppLaunchSettings(): Promise<OpenOemSettingsResult>;
  triggerSyncNow(): Promise<boolean>;
}

export default requireNativeModule<HealthModule>("Health");
