/**
 * Daily Notification Plugin Definitions
 * 
 * TypeScript definitions for the Daily Notification Plugin
 * Aligned with Android implementation and test requirements
 * 
 * @author Matthew Raymer
 * @version 2.1.4 (see package.json for source of truth)
 */

// Import SPI types from content-fetcher.ts
import type {
  SchedulingPolicy,
  JsNotificationContentFetcher
} from './types/content-fetcher';

// Import core types for use in this file
import type {
  Schedule,
  ScheduleWithStatus,
  CreateScheduleInput,
  ContentCache,
  CreateContentCacheInput,
  Config,
  CreateConfigInput,
  Callback,
  CreateCallbackInput,
  History,
  HistoryStats,
} from './core/contracts';

import {
  PermissionState,
  ScheduleKind,
  HistoryKind,
  HistoryOutcome,
  CallbackKind,
  ConfigDataType,
} from './core/enums';

// Re-export core types (canonical source) for external consumers
export type {
  Schedule,
  ScheduleWithStatus,
  CreateScheduleInput,
  ContentCache,
  CreateContentCacheInput,
  Config,
  CreateConfigInput,
  Callback,
  CreateCallbackInput,
  History,
  HistoryStats,
};

export {
  PermissionState,
  ScheduleKind,
  HistoryKind,
  HistoryOutcome,
  CallbackKind,
  ConfigDataType,
};

export interface NotificationResponse {
  id: string;
  title: string;
  body: string;
  timestamp: number;
  url?: string;
}

export interface NotificationOptions {
  url?: string;
  time?: string;
  title?: string;
  body?: string;
  sound?: boolean;
  priority?: 'high' | 'default' | 'low' | 'min' | 'max' | 'normal';
  timezone?: string;
  retryCount?: number;
  retryInterval?: number;
  offlineFallback?: boolean;
  headers?: Record<string, string>;
  /**
   * Optional rollover interval in minutes for dev/testing.
   * When set (e.g. 10), the next occurrence is scheduled this many minutes after the current trigger
   * instead of 24 hours. Persisted with the schedule so it survives reboot. When absent or <= 0, use 24h.
   */
  rolloverIntervalMinutes?: number;
}


export interface NotificationSettings {
  url?: string;
  time?: string;
  sound?: boolean;
  priority?: string;
  timezone?: string;
  retryCount?: number;
  retryInterval?: number;
  offlineFallback?: boolean;
}

export interface NotificationStatus {
  isEnabled?: boolean;
  isScheduled?: boolean;
  lastNotificationTime: number | Promise<number>;
  nextNotificationTime: number | Promise<number>;
  pending?: number;
  settings: NotificationSettings;
  error?: string;
}

export interface BatteryStatus {
  level: number;
  isCharging: boolean;
  powerState: number;
  isOptimizationExempt: boolean;
}

export interface PowerState {
  powerState: number;
  isOptimizationExempt: boolean;
}

export interface NotificationEvent extends Event {
  detail: {
    id: string;
    action: string;
    data?: Record<string, unknown>;
  };
}

export interface PermissionStatus {
  status?: string;
  granted?: boolean;
  notifications: PermissionState;
  backgroundRefresh?: PermissionState; // iOS only
  alert?: boolean;
  badge?: boolean;
  sound?: boolean;
  lockScreen?: boolean;
  carPlay?: boolean;
}

/**
 * Permission status result for checkPermissionStatus()
 * Returns boolean flags for each permission type
 */
export interface PermissionStatusResult {
  notificationsEnabled: boolean;
  exactAlarmEnabled: boolean;
  wakeLockEnabled: boolean;
  allPermissionsGranted: boolean;
}

/** iOS UNUserNotificationCenter authorization flags (diagnostics) */
export interface NotificationPermissionStatus {
  authorized: boolean;
  denied: boolean;
  notDetermined: boolean;
  provisional: boolean;
}

/** Pending UNNotificationRequest snapshot for debug panels (iOS) */
export interface PendingNotificationDiagnostic {
  identifier: string;
  triggerTimestamp: number | null;
  triggerDateIso: string | null;
  title?: string;
  body?: string;
  /** @deprecated Prefer triggerTimestamp */
  triggerDate?: number | null;
  triggerType?: 'calendar' | 'timeInterval' | 'location' | 'unknown';
  repeats?: boolean;
}

export interface PendingNotificationsResult {
  count: number;
  notifications: PendingNotificationDiagnostic[];
}

/** Delivered UNNotification metadata for debug panels (iOS) */
export interface DeliveredNotificationMetadata {
  identifier: string;
  deliveredTimestamp: number;
  deliveredDateIso: string | null;
  title: string;
  body: string;
  categoryIdentifier: string | null;
}

export interface DeliveredNotificationsResult {
  count: number;
  notifications: DeliveredNotificationMetadata[];
}

/**
 * UNNotificationSettings snapshot for debug panels (iOS).
 * Not the app-level {@link NotificationSettings} schedule preferences type.
 */
export interface NotificationCenterSettingsSnapshot {
  authorizationStatus: string;
  notificationCenterSetting: string;
  lockScreenSetting: string;
  carPlaySetting: string;
  alertSetting: string;
  badgeSetting: string;
  soundSetting: string;
  criticalAlertSetting: string;
  showPreviewsSetting: string;
  announcementSetting?: string;
  scheduledDeliverySetting?: string;
  timeSensitiveSetting?: string;
}

/** @deprecated Use PendingNotificationDiagnostic */
export interface PendingNotification {
  identifier: string;
  title: string;
  body: string;
  triggerDate: number;
  triggerType: 'calendar' | 'timeInterval' | 'location';
  repeats: boolean;
}

export interface BackgroundTaskStatus {
  fetchTaskRegistered: boolean;
  notifyTaskRegistered: boolean;
  lastFetchExecution: number | null;
  lastNotifyExecution: number | null;
  backgroundRefreshEnabled: boolean | null;
}

// Static Daily Reminder Interfaces
export interface DailyReminderOptions {
  id: string;
  title: string;
  body: string;
  time: string; // HH:mm format (e.g., "09:00")
  sound?: boolean;
  vibration?: boolean;
  priority?: 'low' | 'normal' | 'high';
  repeatDaily?: boolean;
  timezone?: string;
}

export interface DailyReminderInfo {
  id: string;
  title: string;
  body: string;
  time: string;
  sound: boolean;
  vibration: boolean;
  priority: 'low' | 'normal' | 'high';
  repeatDaily: boolean;
  timezone?: string;
  isScheduled: boolean;
  nextTriggerTime?: number;
  createdAt: number;
  lastTriggered?: number;
}

// PermissionState now exported from ./core/enums

// Additional interfaces for enhanced functionality
export interface NotificationMetrics {
  scheduledTime: number;
  actualDeliveryTime?: number;
  contentAge: number;
  engagement?: 'TAPPED' | 'DISMISSED' | 'IGNORED';
  failureReason?: string;
  platformInfo: PlatformInfo;
}

export interface PlatformInfo {
  oem?: string;
  osVersion: string;
  appState: string;
}

export interface FallbackContent {
  title: string;
  body: string;
  isEmergency: boolean;
  age?: string;
}

export interface CachePolicy {
  maxSize: number;
  evictionPolicy: 'LRU' | 'FIFO' | 'TTL';
  ttl?: number;
  cleanupInterval: number;
}

export interface NetworkConfig {
  timeout: number;
  retryAttempts: number;
  retryDelay: number;
  offlineFallback: boolean;
}

export interface SchedulingConfig {
  exactAlarms: boolean;
  adaptiveScheduling: boolean;
  quietHours?: {
    start: string;
    end: string;
    enabled: boolean;
  };
  timezone: string;
}

export interface ConfigureOptions {
  dbPath?: string;
  storage?: 'shared' | 'tiered';
  ttlSeconds?: number;
  prefetchLeadMinutes?: number;
  maxNotificationsPerDay?: number;
  retentionDays?: number;
  // Phase 2: TimeSafari ActiveDid Integration Enhancement
  activeDidIntegration?: {
    platform: 'android' | 'ios' | 'electron';
    storageType: 'plugin-managed' | 'host-managed';
    jwtExpirationSeconds?: number;
    apiServer?: string;
    // Phase 2: Host-provided activeDid configuration
    activeDid?: string; // Initial activeDid from host
    hostCredentials?: {
      platform?: string; // Platform identifier
      accessToken?: string; // Optional access token
    };
    autoSync?: boolean; // Auto-sync activeDid changes
    identityChangeGraceSeconds?: number; // Grace period for activeDid changes
  };
}

// Dual Scheduling System Interfaces
export interface ContentFetchConfig {
  enabled: boolean;
  schedule: string; // Cron expression
  url?: string;
  headers?: Record<string, string>;
  timeout?: number;
  retryAttempts?: number;
  retryDelay?: number;
  callbacks: {
    apiService?: string;
    database?: string;
    reporting?: string;
    onSuccess?: (data: Record<string, unknown>) => Promise<void>;
    onError?: (error: Error) => Promise<void>;
    onComplete?: (result: ContentFetchResult) => Promise<void>;
  };
  cachePolicy?: CachePolicy;
  networkConfig?: NetworkConfig;
  // Phase 2: TimeSafari Endorser.ch API configuration
  timesafariConfig?: {
    activeDid: string; // Required activeDid for authentication
    endpoints?: {
      offersToPerson?: string;
      offersToPlans?: string;
      projectsLastUpdated?: string;
    };
    syncConfig?: {
      enableParallel?: boolean; // Enable parallel API requests
      maxConcurrent?: number; // Max concurrent requests
      batchSize?: number; // Batch size for requests
    };
    credentialConfig?: {
      jwtSecret?: string; // JWT secret for signing
      tokenExpirationMinutes?: number; // Token expiration
      refreshThresholdMinutes?: number; // Refresh threshold
    };
    errorPolicy?: {
      maxRetries?: number;
      backoffMultiplier?: number;
      activeDidChangeRetries?: number; // Special retry for activeDid changes
    };
  };
}

export interface UserNotificationConfig {
  enabled: boolean;
  schedule: string; // Cron expression
  title?: string;
  body?: string;
  sound?: boolean;
  vibration?: boolean;
  priority?: 'low' | 'normal' | 'high';
  badge?: boolean;
  actions?: NotificationAction[];
  category?: string;
  userInfo?: Record<string, unknown>;
}

export interface NotificationAction {
  id: string;
  title: string;
  icon?: string;
  destructive?: boolean;
  authenticationRequired?: boolean;
}

export interface DualScheduleConfiguration {
  contentFetch: ContentFetchConfig;
  userNotification: UserNotificationConfig;
  relationship?: {
    autoLink: boolean;        // Automatically link content to notification
    contentTimeout: number;   // How long to wait for content before notification
    fallbackBehavior: 'skip' | 'show_default' | 'retry';
  };
}

export interface ContentFetchResult {
  success: boolean;
  data?: Record<string, unknown>;
  timestamp: number;
  contentAge: number;
  error?: string;
  retryCount: number;
  metadata?: Record<string, unknown>;
}

// ============================================================================
// DATABASE TYPE DEFINITIONS
// ============================================================================
// These types represent the plugin's internal SQLite database schema.
// The plugin owns its database, and these types are used for TypeScript
// access through Capacitor interfaces.
//
// See: doc/DATABASE_INTERFACES.md for complete documentation
// ============================================================================

// Core contracts (Schedule, ContentCache, Config, Callback, History) now exported from ./core/contracts

export interface DualScheduleStatus {
  contentFetch: {
    isEnabled: boolean;
    isScheduled: boolean;
    lastFetchTime?: number;
    nextFetchTime?: number;
    lastFetchResult?: ContentFetchResult;
    pendingFetches: number;
  };
  userNotification: {
    isEnabled: boolean;
    isScheduled: boolean;
    lastNotificationTime?: number;
    nextNotificationTime?: number;
    pendingNotifications: number;
  };
  relationship: {
    isLinked: boolean;
    contentAvailable: boolean;
    lastLinkTime?: number;
  };
  overall: {
    isActive: boolean;
    lastActivity: number;
    errorCount: number;
    successRate: number;
  };
}

// Enhanced DailyNotificationPlugin interface with dual scheduling
export interface DailyNotificationPlugin {
  // Configuration methods
  configure(options: ConfigureOptions): Promise<void>;
  
  /**
   * Configure native fetcher with API credentials (cross-platform)
   * 
   * This method provides a cross-platform mechanism for passing API credentials
   * from TypeScript/JavaScript code to native fetcher implementations. The
   * configuration is passed directly without using platform-specific storage
   * mechanisms, keeping the interface consistent across Android, iOS, and web.
   * 
   * **Why this exists:**
   * - Native fetchers run in background workers (WorkManager/BGTaskScheduler)
   * - Background workers cannot access JavaScript variables or Capacitor bridge
   * - This method provides direct injection without storage dependencies
   * 
   * **When to call:**
   * - After app startup, once API credentials are available
   * - After user login/authentication, when activeDid changes
   * - When API server URL changes (dev/staging/production)
   * 
   * **Prerequisites:**
   * - Native fetcher must be registered in `Application.onCreate()` (Android)
   *   or `AppDelegate.didFinishLaunching()` (iOS) BEFORE calling this method
   * - Should be called before any background fetches occur
   * 
   * **Thread Safety:**
   * - Safe to call from any thread (main thread or background)
   * - Configuration changes take effect immediately for subsequent fetches
   * - Native implementations should use `volatile` fields for thread safety
   * 
   * **Example:**
   * ```typescript
   * import { DailyNotification } from '@capacitor-community/daily-notification';
   * 
   * await DailyNotification.configureNativeFetcher({
   *   apiBaseUrl: 'http://10.0.2.2:3000',  // Android emulator → host localhost
   *   activeDid: 'did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F',
   *   jwtSecret: 'test-jwt-secret-for-development'
   * });
   * ```
   * 
   * **Error Handling:**
   * - Rejects if required parameters are missing
   * - Rejects if no native fetcher is registered
   * - Rejects if native fetcher's `configure()` throws exception
   * 
   * @param options Configuration options:
   *                - `apiBaseUrl` (required): Base URL for API server.
   *                  - Android emulator: `"http://10.0.2.2:3000"` (maps to host localhost:3000)
   *                  - iOS simulator: `"http://localhost:3000"`
   *                  - Production: `"https://api.timesafari.com"`
   *                - `activeDid` (required): Active DID for authentication.
   *                  Format: `"did:ethr:0x..."`. Used as JWT issuer/subject.
   *                - `jwtToken` (required): Pre-generated JWT token (ES256K signed).
   *                  Generated in TypeScript using TimeSafari's `createEndorserJwtForKey()` function.
   *                  **Note**: Token should be ES256K signed (DID-based), not HS256.
   * 
   * **Architecture Note**: JWT tokens should be generated in TypeScript using TimeSafari's
   * `createEndorserJwtForKey()` function (which uses DID-based ES256K signing), then passed
   * to this method. This avoids the complexity of implementing DID-based JWT signing in Java.
   * 
   * @throws {Error} If configuration fails (missing params, no fetcher registered, etc.)
   * 
   * @see {@link https://gitea.anomalistdesign.com/trent_larson/daily-notification-plugin/blob/main/doc/architecture/NATIVE_FETCHER_CONFIGURATION.md | Native Fetcher Configuration Guide}
   *      for complete documentation and examples
   */
  configureNativeFetcher(options: {
    apiBaseUrl: string;
    activeDid: string;
    /** Primary token; keep for backward compatibility and single-JWT flows. */
    jwtToken: string;
    /**
     * Optional. Distinct JWT strings for background use (e.g. one per day slot).
     * Persisted with native config when `persistToken` is true (same as primary token).
     * If omitted or empty, behavior matches a single `jwtToken` only.
     */
    jwtTokens?: string[];
    /**
     * Optional alternative to `jwtTokens` when bridge payload size matters: JSON array string of JWT strings.
     */
    jwtTokenPoolJson?: string;
  }): Promise<void>;
  
  // Rolling window management
  maintainRollingWindow(): Promise<void>;
  getRollingWindowStats(): Promise<{
    stats: string;
    maintenanceNeeded: boolean;
    timeUntilNextMaintenance: number;
  }>;
  
  // Exact alarm management
  getExactAlarmStatus(): Promise<{
    supported: boolean;
    enabled: boolean;
    canSchedule: boolean;
    fallbackWindow: string;
  }>;
  requestExactAlarmPermission(): Promise<void>;
  openExactAlarmSettings(): Promise<void>;
  
  // Reboot recovery management
  getRebootRecoveryStatus(): Promise<{
    inProgress: boolean;
    lastRecoveryTime: number;
    timeSinceLastRecovery: number;
    recoveryNeeded: boolean;
  }>;
  
  // Existing methods
  scheduleDailyNotification(options: NotificationOptions): Promise<void>;
  
  /**
   * Check if an alarm is scheduled for a given trigger time
   * @param options Object containing triggerAtMillis (number)
   * @returns Object with scheduled (boolean) and triggerAtMillis (number)
   */
  isAlarmScheduled(options: { triggerAtMillis: number }): Promise<{ scheduled: boolean; triggerAtMillis: number }>;
  
  /**
   * Get the next scheduled alarm time from AlarmManager
   * @returns Object with scheduled (boolean) and triggerAtMillis (number | null)
   */
  getNextAlarmTime(): Promise<{ scheduled: boolean; triggerAtMillis?: number }>;
  
  /**
   * Test method: Schedule an alarm to fire in a few seconds
   * Useful for verifying alarm delivery works correctly
   * @param options Object containing secondsFromNow (number, default: 5)
   * @returns Object with scheduled (boolean), secondsFromNow (number), and triggerAtMillis (number)
   */
  testAlarm(options?: { secondsFromNow?: number }): Promise<{ scheduled: boolean; secondsFromNow: number; triggerAtMillis: number }>;
  
  getLastNotification(): Promise<NotificationResponse | null>;
  cancelAllNotifications(): Promise<void>;
  /**
   * Add one-shot API-managed notifications at epoch-ms timestamps (additive).
   * Uses `api_<timestamp>` identifiers; caller should clear first when replacing a batch.
   */
  scheduleApiNotifications(options: { timestamps: number[] }): Promise<void>;
  /**
   * Cancel API-managed notifications (`api_*`) without affecting Daily Reminders
   * (iOS: `daily_*`; Android: `daily_notification` / caller id), user schedules,
   * dual schedules, or fetch jobs.
   */
  clearApiNotifications(): Promise<void>;
  getNotificationStatus(): Promise<NotificationStatus>;
  updateSettings(settings: NotificationSettings): Promise<void>;
  getBatteryStatus(): Promise<BatteryStatus>;
  requestBatteryOptimizationExemption(): Promise<void>;
  setAdaptiveScheduling(options: { enabled: boolean }): Promise<void>;
  getPowerState(): Promise<PowerState>;
  checkPermissions(): Promise<PermissionStatus>;
  requestPermissions(): Promise<PermissionStatus>;
  checkPermissionStatus(): Promise<PermissionStatusResult>;
  requestNotificationPermissions(): Promise<PermissionStatus>;
  isChannelEnabled(channelId?: string): Promise<{ enabled: boolean; channelId: string }>;
  openChannelSettings(channelId?: string): Promise<void>;
  checkStatus(): Promise<NotificationStatus>;

  // iOS local notification diagnostics (bridge-safe, no backend concepts)
  getPendingNotifications(): Promise<PendingNotificationsResult>;
  getDeliveredNotifications(): Promise<DeliveredNotificationsResult>;
  getNotificationSettings(): Promise<NotificationCenterSettingsSnapshot>;
  getNotificationPermissionStatus(): Promise<NotificationPermissionStatus>;
  requestNotificationPermission(): Promise<{ granted: boolean }>;
  getBackgroundTaskStatus(): Promise<BackgroundTaskStatus>;
  openNotificationSettings(): Promise<void>;
  openBackgroundAppRefreshSettings(): Promise<void>;
  
  // New dual scheduling methods
  scheduleContentFetch(config: ContentFetchConfig): Promise<void>;
  scheduleUserNotification(config: UserNotificationConfig): Promise<void>;
  scheduleDualNotification(config: DualScheduleConfiguration): Promise<void>;
  getDualScheduleStatus(): Promise<DualScheduleStatus>;
  updateDualScheduleConfig(config: DualScheduleConfiguration): Promise<void>;
  cancelDualSchedule(): Promise<void>;
  pauseDualSchedule(): Promise<void>;
  resumeDualSchedule(): Promise<void>;
  
  // Content management methods
  getContentCache(): Promise<Record<string, unknown>>;
  clearContentCache(): Promise<void>;
  getContentHistory(): Promise<ContentFetchResult[]>;
  
  // Callback management methods
  registerCallback(name: string, callback: (...args: unknown[]) => void): Promise<void>;
  unregisterCallback(name: string): Promise<void>;
  getRegisteredCallbacks(): Promise<string[]>;
  
  // ============================================================================
  // DATABASE ACCESS METHODS
  // ============================================================================
  // These methods provide TypeScript/JavaScript access to the plugin's internal
  // SQLite database. Since the plugin owns its database, the host app/webview
  // accesses data through these Capacitor interfaces.
  //
  // Usage Pattern:
  //   import { DailyNotification } from '@capacitor-community/daily-notification';
  //   const schedules = await DailyNotification.getSchedules({ kind: 'notify' });
  //
  // See: doc/DATABASE_INTERFACES.md for complete documentation
  // ============================================================================
  
  /**
   * Get all schedules matching optional filters
   * 
   * @param options Optional filters:
   *   - kind: Filter by schedule type ('fetch' | 'notify')
   *   - enabled: Filter by enabled status (true = only enabled, false = only disabled, undefined = all)
   * @returns Promise resolving to object with schedules array: { schedules: Schedule[] }
   * 
   * @example
   * ```typescript
   * // Get all enabled notification schedules
   * const result = await DailyNotification.getSchedules({ 
   *   kind: 'notify', 
   *   enabled: true 
   * });
   * const schedules = result.schedules;
   * ```
   */
  getSchedules(options?: { kind?: 'fetch' | 'notify'; enabled?: boolean }): Promise<{ schedules: Schedule[] }>;
  
  /**
   * Get all schedules with their AlarmManager status
   * Returns schedules from database with isActuallyScheduled flag for each
   * 
   * @param options Optional filters:
   *   - kind: Filter by schedule type ('fetch' | 'notify')
   *   - enabled: Filter by enabled status (true = only enabled, false = only disabled, undefined = all)
   * @returns Promise resolving to object with schedules array: { schedules: ScheduleWithStatus[] }
   * 
   * @example
   * ```typescript
   * // Get all notification schedules with AlarmManager status
   * const result = await DailyNotification.getSchedulesWithStatus({ 
   *   kind: 'notify', 
   *   enabled: true 
   * });
   * result.schedules.forEach(schedule => {
   *   console.log(schedule.id + ': ' + (schedule.isActuallyScheduled ? 'Scheduled' : 'Not scheduled'));
   * });
   * ```
   */
  getSchedulesWithStatus(options?: { kind?: 'fetch' | 'notify'; enabled?: boolean }): Promise<{ schedules: ScheduleWithStatus[] }>;
  
  /**
   * Get a single schedule by ID
   * 
   * @param id Schedule ID
   * @returns Promise resolving to Schedule object or null if not found
   */
  getSchedule(id: string): Promise<Schedule | null>;
  
  /**
   * Create a new recurring schedule
   * 
   * @param schedule Schedule configuration object with:
   *   - `id` (required): Unique schedule identifier (must be unique)
   *   - `kind`: Schedule type: 'notify' for notifications, 'fetch' for content fetching
   *   - `cron`: Cron expression (e.g., '0 9 * * *' for daily at 9 AM). Mutually exclusive with clockTime
   *   - `clockTime`: Time of day in HH:mm format (e.g., '09:00'). Mutually exclusive with cron
   *   - `enabled`: Whether schedule is active (default: true)
   *   - `jitterMs`: Random jitter in milliseconds (default: 0)
   *   - `backoffPolicy`: Backoff policy for retries (default: 'exp')
   * @returns Promise resolving to created Schedule object
   * @throws {DailyNotificationError} If schedule creation fails (e.g., invalid cron, duplicate ID, permission denied)
   * 
   * @example
   * ```typescript
   * const schedule = await DailyNotification.createSchedule({
   *   id: 'morning-notification',
   *   kind: 'notify',
   *   clockTime: '09:00',
   *   enabled: true
   * });
   * ```
   * 
   * @example
   * ```typescript
   * // Using cron expression
   * const schedule = await DailyNotification.createSchedule({
   *   id: 'daily-fetch',
   *   kind: 'fetch',
   *   cron: '0 0,6,12,18 * * *',
   *   enabled: true
   * });
   * ```
   */
  createSchedule(schedule: CreateScheduleInput): Promise<Schedule>;
  
  /**
   * Update an existing schedule
   * 
   * @param id Schedule ID (required)
   * @param updates Partial schedule updates. Only provided fields will be updated.
   * @returns Promise resolving to updated Schedule object
   * @throws {DailyNotificationError} If schedule not found, invalid updates, or permission denied
   * 
   * @example
   * ```typescript
   * // Update schedule time
   * const updated = await DailyNotification.updateSchedule('morning-notification', {
   *   clockTime: '10:00'
   * });
   * ```
   * 
   * @example
   * ```typescript
   * // Disable a schedule
   * await DailyNotification.updateSchedule('morning-notification', {
   *   enabled: false
   * });
   * ```
   */
  updateSchedule(id: string, updates: Partial<Schedule>): Promise<Schedule>;
  
  /**
   * Delete a schedule
   * 
   * @param id Schedule ID (required)
   * @returns Promise resolving when deletion completes
   * @throws {DailyNotificationError} If schedule not found or deletion fails
   * 
   * @example
   * ```typescript
   * await DailyNotification.deleteSchedule('morning-notification');
   * ```
   */
  deleteSchedule(id: string): Promise<void>;
  
  /**
   * Enable or disable a schedule
   * 
   * @param id Schedule ID (required)
   * @param enabled Enable state (true to enable, false to disable)
   * @returns Promise resolving when update completes
   * @throws {DailyNotificationError} If schedule not found or update fails
   * 
   * @example
   * ```typescript
   * // Enable a schedule
   * await DailyNotification.enableSchedule('morning-notification', true);
   * 
   * // Disable a schedule
   * await DailyNotification.enableSchedule('morning-notification', false);
   * ```
   */
  enableSchedule(id: string, enabled: boolean): Promise<void>;
  
  /**
   * Calculate next run time from a cron expression or clockTime
   * 
   * @param schedule Cron expression (e.g., "0 9 * * *") or clockTime (e.g., "09:00")
   * @returns Promise resolving to timestamp (milliseconds since epoch)
   */
  calculateNextRunTime(schedule: string): Promise<number>;
  
  /**
   * Get content cache by ID or latest cache
   * 
   * @param options Optional filters:
   *   - id: Specific cache ID (if not provided, returns latest)
   * @returns Promise resolving to ContentCache object or null
   */
  getContentCacheById(options?: { id?: string }): Promise<ContentCache | null>;
  
  /**
   * Get the latest content cache entry
   * 
   * @returns Promise resolving to latest ContentCache object or null
   */
  getLatestContentCache(): Promise<ContentCache | null>;
  
  /**
   * Get content cache history
   * 
   * @param limit Maximum number of entries to return (default: 10)
   * @returns Promise resolving to object with history array: { history: ContentCache[] }
   */
  getContentCacheHistory(limit?: number): Promise<{ history: ContentCache[] }>;
  
  /**
   * Save content to cache
   * 
   * @param content Content cache data
   * @returns Promise resolving to saved ContentCache object
   */
  saveContentCache(content: CreateContentCacheInput): Promise<ContentCache>;
  
  /**
   * Clear content cache entries
   * 
   * @param options Optional filters:
   *   - olderThan: Only clear entries older than this timestamp (milliseconds)
   * @returns Promise resolving when cleanup completes
   */
  clearContentCacheEntries(options?: { olderThan?: number }): Promise<void>;
  
  /**
   * Get configuration value
   * 
   * @param key Configuration key
   * @param options Optional filters:
   *   - timesafariDid: Filter by TimeSafari DID
   * @returns Promise resolving to Config object or null
   */
  getConfig(key: string, options?: { timesafariDid?: string }): Promise<Config | null>;
  
  /**
   * Get all configurations matching filters
   * 
   * @param options Optional filters:
   *   - timesafariDid: Filter by TimeSafari DID
   *   - configType: Filter by configuration type
   * @returns Promise resolving to array of Config objects
   */
  getAllConfigs(options?: { timesafariDid?: string; configType?: string }): Promise<{ configs: Config[] }>;
  
  /**
   * Set configuration value
   * 
   * @param config Configuration data
   * @returns Promise resolving to saved Config object
   */
  setConfig(config: CreateConfigInput): Promise<Config>;
  
  /**
   * Update configuration value
   * 
   * @param key Configuration key
   * @param value New value (will be stringified based on dataType)
   * @param options Optional filters:
   *   - timesafariDid: Filter by TimeSafari DID
   * @returns Promise resolving to updated Config object
   */
  updateConfig(key: string, value: string, options?: { timesafariDid?: string }): Promise<Config>;
  
  /**
   * Delete configuration
   * 
   * @param key Configuration key
   * @param options Optional filters:
   *   - timesafariDid: Filter by TimeSafari DID
   * @returns Promise resolving when deletion completes
   */
  deleteConfig(key: string, options?: { timesafariDid?: string }): Promise<void>;
  
  /**
   * Get all callbacks matching filters
   * 
   * @param options Optional filters:
   *   - enabled: Filter by enabled status
   * @returns Promise resolving to object with callbacks array: { callbacks: Callback[] }
   */
  getCallbacks(options?: { enabled?: boolean }): Promise<{ callbacks: Callback[] }>;
  
  /**
   * Get a single callback by ID
   * 
   * @param id Callback ID
   * @returns Promise resolving to Callback object or null
   */
  getCallback(id: string): Promise<Callback | null>;
  
  /**
   * Register a new callback
   * 
   * @param callback Callback configuration
   * @returns Promise resolving to created Callback object
   */
  registerCallbackConfig(callback: CreateCallbackInput): Promise<Callback>;
  
  /**
   * Update an existing callback
   * 
   * @param id Callback ID
   * @param updates Partial callback updates
   * @returns Promise resolving to updated Callback object
   */
  updateCallback(id: string, updates: Partial<Callback>): Promise<Callback>;
  
  /**
   * Delete a callback
   * 
   * @param id Callback ID
   * @returns Promise resolving when deletion completes
   */
  deleteCallback(id: string): Promise<void>;
  
  /**
   * Enable or disable a callback
   * 
   * @param id Callback ID
   * @param enabled Enable state
   * @returns Promise resolving when update completes
   */
  enableCallback(id: string, enabled: boolean): Promise<void>;
  
  /**
   * Get execution history
   * 
   * @param options Optional filters:
   *   - since: Only return entries after this timestamp (milliseconds)
   *   - kind: Filter by execution kind ('fetch' | 'notify' | 'callback')
   *   - limit: Maximum number of entries to return (default: 50)
   * @returns Promise resolving to object with history array: { history: History[] }
   */
  getHistory(options?: { 
    since?: number; 
    kind?: 'fetch' | 'notify' | 'callback'; 
    limit?: number;
  }): Promise<{ history: History[] }>;
  
  /**
   * Get history statistics
   * 
   * @returns Promise resolving to history statistics
   */
  getHistoryStats(): Promise<HistoryStats>;
  
  // Phase 1: ActiveDid Management Methods (Option A Implementation)
  setActiveDidFromHost(activeDid: string): Promise<void>;
  onActiveDidChange(callback: (newActiveDid: string) => Promise<void>): void;
  refreshAuthenticationForNewIdentity(activeDid: string): Promise<void>;
  clearCacheForNewIdentity(): Promise<void>;
  updateBackgroundTaskIdentity(activeDid: string): Promise<void>;

  // Starred Plans Management Methods
  /**
   * Update starred plan IDs from host application
   * 
   * This allows the TimeSafari app to dynamically update the list of starred
   * project IDs when users star or unstar projects. The IDs are stored persistently
   * and used for prefetch operations that query for starred project updates.
   * 
   * @param options Contains:
   *   - planIds: string[] - Array of starred plan handle IDs
   * @returns Promise with success status and plan count
   */
  updateStarredPlans(options: { planIds: string[] }): Promise<{
    success: boolean;
    planIdsCount: number;
    updatedAt: number;
  }>;

  /**
   * Get current starred plan IDs
   * 
   * Returns the currently stored starred plan IDs from SharedPreferences.
   * This is useful for the host app to verify what IDs are stored.
   * 
   * @returns Promise with current starred plan IDs
   */
  getStarredPlans(): Promise<{
    planIds: string[];
    count: number;
    updatedAt: number;
  }>;

  // Content Fetching Methods
  /**
   * Trigger an immediate standalone fetch for content updates
   * 
   * This method allows manual triggering of content fetches independently of 
   * scheduled notifications. Useful for on-demand content refresh, cache warming,
   * or background sync operations.
   * 
   * @returns Promise with success status and message
   */
  triggerImmediateFetch(): Promise<{
    success: boolean;
    message: string;
  }>;

  // Static Daily Reminder Methods
  /**
   * Schedule a simple daily reminder notification.
   * No network content required — just static text.
   * iOS uses `daily_<reminderId>` identifiers (separate from API-managed `api_*`).
   */
  scheduleDailyReminder(options: DailyReminderOptions): Promise<void>;

  /**
   * Cancel a daily reminder notification
   */
  cancelDailyReminder(reminderId: string): Promise<void>;

  /**
   * Get all scheduled daily reminders
   */
  getScheduledReminders(): Promise<DailyReminderInfo[]>;

  /**
   * Update an existing daily reminder
   */
  updateDailyReminder(reminderId: string, options: DailyReminderOptions): Promise<void>;

  // Integration Point Refactor (PR1): SPI Registration Methods
  
  /**
   * Set JavaScript content fetcher for foreground operations
   * 
   * NOTE: This is a stub in PR1. Full implementation coming in PR3.
   * JS fetchers are ONLY used for foreground/manual refresh.
   * Background workers must use native fetcher.
   * 
   * @param fetcher JavaScript fetcher implementation
   */
  setJsContentFetcher(fetcher: JsNotificationContentFetcher): void;

  /**
   * Enable or disable native fetcher
   * 
   * Native fetcher is required for background workers. If disabled,
   * background fetches will fail gracefully.
   * 
   * @param enable Whether to enable native fetcher
   * @returns Promise with enabled and registered status
   */
  enableNativeFetcher(enable: boolean): Promise<{
    enabled: boolean;
    registered: boolean;
  }>;

  /**
   * Set scheduling policy configuration
   * 
   * Updates the scheduling policy used by the plugin for retry backoff,
   * prefetch timing, deduplication, and cache TTL.
   * 
   * @param policy Scheduling policy configuration
   */
  setPolicy(policy: SchedulingPolicy): Promise<void>;
}

// Phase 1: TimeSafari Endorser.ch API Interfaces
export interface OffersResponse {
  data: OfferSummaryRecord[];
  hitLimit: boolean;
}

export interface OfferSummaryRecord {
  jwtId: string;
  handleId: string;
  issuedAt: string;
  offeredByDid: string;
  recipientDid: string;
  unit: string;
  amount: number;
  amountGiven: number;
  amountGivenConfirmed: number;
  objectDescription: string;
  validThrough?: string;
  fullClaim?: Record<string, unknown>;
}

export interface OffersToPlansResponse {
  data: OfferToPlanSummaryRecord[];
  hitLimit: boolean;
}

export interface OfferToPlanSummaryRecord {
  jwtId: string;
  planId: string;
  handleId: string;
  issuedAt: string;
  offeredByDid: string;
  unit: string;
  amount: number;
  amountGiven: number;
  objectDescription: string;
  validThrough?: string;
}

export interface PlansLastUpdatedResponse {
  data: PlanSummaryWithPreviousClaim[];
  hitLimit: boolean;
}

export interface PlanSummaryWithPreviousClaim {
  plan: PlanSummary;
  wrappedClaimBefore?: Record<string, unknown>;
}

export interface PlanSummary {
  jwtId: string;
  handleId: string;
  name: string;
  description: string;
  issuerDid: string;
  agentDid: string;
  startTime: string;
  endTime: string;
  locLat?: number;
  locLon?: number;
  url?: string;
}

// Phase 2: Detailed TimeSafari Notification Types
export interface TimeSafariNotificationBundle {
  offersToPerson?: OffersResponse;
  offersToProjects?: OffersToPlansResponse;
  projectUpdates?: PlansLastUpdatedResponse;
  fetchTimestamp: number;
  success: boolean;
  error?: string;
  metadata?: {
    activeDid: string;
    fetchDurationMs: number;
    cachedResponses: number;
    networkResponses: number;
  };
}

export interface TimeSafariUserConfig {
  activeDid: string; // Required for all operations
  lastKnownOfferId?: string;
  lastKnownPlanId?: string;
  starredPlanIds?: string[];
  fetchOffersToPerson?: boolean;
  fetchOffersToProjects?: boolean;
  fetchProjectUpdates?: boolean;
  notificationPreferences?: {
    offers: boolean;
    projects: boolean;
    people: boolean;
    items: boolean;
  };
}

// Enhanced notification types per specification
export interface TimeSafariOfferNotification {
  type: 'offer';
  subtype: 'new_to_me' | 'changed_to_me' | 'new_to_projects' | 'changed_to_projects' | 'new_to_favorites' | 'changed_to_favorites';
  offer: OfferSummaryRecord;
  relevantProjects?: PlanSummary[];
  notificationPriority: 'high' | 'medium' | 'low';
}

export interface TimeSafariProjectNotification {
  type: 'project';
  subtype: 'local_and_new' | 'local_and_changed' | 'with_content_and_new' | 'favorite_and_changed';
  project: PlanSummary;
  changes?: {
    fields: string[];
    previousValues?: Record<string, unknown>;
  };
  relevantOffers?: OfferSummaryRecord[];
  notificationPriority: 'high' | 'medium' | 'low';
}

export interface TimeSafariPersonNotification {
  type: 'person';
  subtype: 'local_and_new' | 'local_and_changed' | 'with_content_and_new' | 'favorite_and_changed';
  personDid: string;
  changes?: {
    fields: string[];
    previousValues?: Record<string, unknown>;
  };
  relevantProjects?: PlanSummary[];
  notificationPriority: 'high' | 'medium' | 'low';
}

export interface TimeSafariItemNotification {
  type: 'item';
  subtype: 'local_and_new' | 'local_and_changed' | 'favorite_and_changed';
  itemId: string;
  changes?: {
    fields: string[];
    previousValues?: Record<string, unknown>;
  };
  relevantContext?: 'project' | 'offer' | 'person';
  notificationPriority: 'high' | 'medium' | 'low';
}

// Union type for TimeSafari notifications
export type TimeSafariNotification = 
  | TimeSafariOfferNotification 
  | TimeSafariProjectNotification 
  | TimeSafariPersonNotification 
  | TimeSafariItemNotification;

// Enhanced ActiveDid Management Events
export interface ActiveDidChangeEventEnhanced extends ActiveDidChangeEvent {
  sourceComponent: string; // 'host' | 'plugin' | 'background' | 'sync'
  changeReason: 'user_switch' | 'session_expired' | 'background_refresh' | 'setup';
  transitionDurationMs?: number;
  relatedNotifications?: TimeSafariNotification[];
}

// TimeSafari-specific Platform Configuration
export interface TimeSafariPlatformConfig {
  platform: 'android' | 'ios' | 'electron';
  storageType: 'plugin-managed' | 'host-managed';
  syncStrategy: 'immediate' | 'batched' | 'scheduled';
  permissions: {
    notifications: boolean;
    backgroundRefresh: boolean;
    networkAccess: boolean;
  };
  capabilities: {
    pushNotifications: boolean;
    backgroundTasks: boolean;
    identityManagement: boolean;
    cryptoSigning: boolean;
  };
}

export interface ActiveDidIntegrationConfig {
  platform: 'android' | 'ios' | 'electron';
  storageType: 'plugin-managed' | 'host-managed';
  jwtExpirationSeconds?: number;
  apiServer?: string;
}

export interface ActiveDidChangeEvent {
  activeDid: string;
  timestamp: number;
  source: 'host' | 'plugin';
}

// MARK: - Phase 3: TimeSafari Background Coordination Interfaces

/**
 * Phase 3: Extended DailyNotificationPlugin interface with TimeSafari coordination
 */
export interface EnhancedDailyNotificationPlugin extends DailyNotificationPlugin {
  // Phase 1: ActiveDid Management (already extended in parent)
  
  // Phase 3: TimeSafari Background Coordination
  coordinateBackgroundTasks(): Promise<void>;
  handleAppLifecycleEvent(event: AppLifecycleEvent): Promise<void>;
  getCoordinationStatus(): Promise<CoordinationStatus>;
}

/**
 * Phase 3: App lifecycle events for TimeSafari coordination
 */
export type AppLifecycleEvent = 
  | 'app_background'
  | 'app_foreground' 
  | 'app_resumed'
  | 'app_paused'
  | 'app_visibility_change'
  | 'app_hidden'
  | 'app_visible'
  | 'app_blur'
  | 'app_focus';

/**
 * Phase 3: Coordination status for debugging and monitoring
 */
export interface CoordinationStatus {
  platform: 'android' | 'ios' | 'electron';
  coordinationActive: boolean;
  coordinationPaused: boolean;
  autoSync?: boolean;
  appBackgrounded?: boolean;
  appHidden?: boolean;
  visibilityState?: DocumentVisibilityState;
  focused?: boolean;
  lastActiveDidChange?: number;
  lastCoordinationTimestamp?: number;
  lastAppBackgrounded?: number;
  lastAppForegrounded?: number;
  lastCoordinationSuccess?: number;
  lastCoordinationFailure?: number;
  coordinationErrors?: string[];
  activeDidTracking?: string;
}

/**
 * Phase 3: PlatformServiceMixin coordination configuration
 */
export interface PlatformServiceMixinConfig {
  enableAutoCoordination?: boolean;
  coordinationTimeout?: number; // Max time for coordination attempts
  enableLifecycleEvents?: boolean;
  enableBackgroundSync?: boolean;
  enableStatePersistence?: boolean;
  coordinationGracePeriod?: number; // Grace period for coordination
  eventHandlers?: {
    [K in AppLifecycleEvent]?: () => Promise<void>;
  };
}

/**
 * Phase 3: WorkManager coordination data
 */
export interface WorkManagerCoordinationData {
  timesafariCoordination: boolean;
  coordinationTimestamp: number;
  activeDidTracking: string;
  platformCoordinationVersion?: number;
  coordinationTimeouts?: {
    maxCoordinationAge: number;
    maxExecutionTime: number;
    maxRetryAge: number;
  };
}

/**
 * Phase 3: Background execution constraints
 */
export interface BackgroundExecutionConstraints {
  devicePowerMode?: 'normal' | 'low_power' | 'critical';
  appForegroundState?: 'foreground' | 'background' | 'inactive';
  activeDidStability?: 'stable' | 'changing' | 'unknown';
  coordinationFreshness?: 'fresh' | 'stale' | 'expired';
  networkAvailability?: 'cellular' | 'wifi' | 'offline';
  batteryLevel?: 'high' | 'medium' | 'low' | 'critical';
}

/**
 * Phase 3: Coordination report
 */
export interface CoordinationReport {
  success: boolean;
  operation: string;
  duration: number;
  constraints: BackgroundExecutionConstraints;
  errors?: string[];
  timestamp: number;
  activeDid?: string;
  authUsed: boolean;
  platformSpecific?: Record<string, unknown>;
}

/**
 * Phase 3: TimeSafari state synchronization data
 */
export interface TimeSafariSyncData {
  authenticationState: {
    activeDid: string;
    jwtExpiration?: number;
    tokenRefreshNeeded: boolean;
  };
  notificationState: {
    lastDelivery: number;
    lastDeliveryId?: string;
    pendingDeliveries: string[];
  };
  backgroundTaskState: {
    lastBackgroundExecution: number;
    lastCoordinationSuccess: number;
    pendingCoordinationTasks: string[];
  };
  activeDidHistory: {
    changes: Array<{
      did: string;
      timestamp: number;
      source: string;
    }>;
    pendingUpdates: string[];
  };
}

// MARK: - Phase 4: TimeSafari Notification Types

/**
 * Phase 4: TimeSafari-specific notification interfaces
 */
export interface TimeSafariNotificationBundle {
  offersToPerson?: OffersResponse;
  offersToProjects?: OffersToPlansResponse;
  projectUpdates?: PlansLastUpdatedResponse;
  fetchTimestamp: number;
  success: boolean;
  error?: string;
  metadata?: {
    activeDid: string;
    fetchDurationMs: number;
    cachedResponses: number;
    networkResponses: number;
  };
}

export interface TimeSafariUserConfig {
  activeDid: string;
  starredPlanIds?: string[];
  lastKnownOfferId?: string;
  lastKnownPlanId?: string;
  fetchOffersToPerson?: boolean;
  fetchOffersToProjects?: boolean;
  fetchProjectUpdates?: boolean;
  notificationPreferences?: {
    offers: boolean;
    projects: boolean;
    people: boolean;
    items: boolean;
  };
}

// TimeSafari notification subtype types
export type TimeSafariOfferSubtype = 
  | 'new_to_me' 
  | 'changed_to_me' 
  | 'new_to_projects' 
  | 'changed_to_projects' 
  | 'new_to_favorites' 
  | 'changed_to_favorites';

export type TimeSafariProjectSubtype = 
  | 'local_and_new' 
  | 'local_and_changed' 
  | 'with_content_and_new' 
  | 'favorite_and_changed';

export type TimeSafariPersonSubtype = 
  | 'local_and_new' 
  | 'local_and_changed' 
  | 'with_content_and_new' 
  | 'favorite_and_changed';

export type TimeSafariItemSubtype = 
  | 'local_and_new' 
  | 'local_and_changed' 
  | 'favorite_and_changed';

// Individual notification interfaces
export interface TimeSafariOfferNotification {
  type: 'offer';
  subtype: TimeSafariOfferSubtype;
  offer: OfferSummaryRecord; // Simplified to single type initially
  relevantProjects?: PlanSummary[];
  notificationPriority: 'high' | 'medium' | 'low';
  timestamp: number;
}

export interface TimeSafariProjectNotification {
  type: 'project';
  subtype: TimeSafariProjectSubtype;
  project: PlanSummary;
  previousClaim?: Record<string, unknown>; // Previous claim data
  notificationPriority: 'high' | 'medium' | 'low';
  timestamp: number;
}

export interface TimeSafariPersonNotification {
  type: 'person';
  subtype: TimeSafariPersonSubtype;
  person: {
    did: string;
    name?: string;
  };
  notificationPriority: 'high' | 'medium' | 'low';
  timestamp: number;
  personDid: string; // Add missing property
}

export interface TimeSafariItemNotification {
  type: 'item';
  subtype: TimeSafariItemSubtype;
  item: {
    id: string;
    name?: string;
    type?: string;
  };
  notificationPriority: 'high' | 'medium' | 'low';
  timestamp: number;
  itemId: string; // Add missing property
}

// Union type for all TimeSafari notification types
export type TimeSafariNotificationType = 
  | TimeSafariOfferNotification 
  | TimeSafariProjectNotification 
  | TimeSafariPersonNotification 
  | TimeSafariItemNotification;

// Enhanced notification interface for Phase 4
export interface EnhancedTimeSafariNotification {
  type: 'offer' | 'project' | 'person' | 'item';
  subtype: string;
  notificationPriority: 'high' | 'medium' | 'low';
  timestamp: number;
  disabled: boolean;
  sound: boolean;
  vibration: boolean;
  badge: boolean;
  priority: 'low' | 'normal' | 'high';
  metadata?: {
    generatedAt: number;
    platform: string;
    userDid?: string;
    preferencesVersion?: number;
    fallback?: boolean;
    message?: string;
  };
  // Type-specific properties (union approach)
  offer?: OfferSummaryRecord;
  project?: PlanSummary;
  person?: { did: string; name?: string };
  item?: { id: string; name?: string; type?: string };
  relevantProjects?: PlanSummary[];
  previousClaim?: Record<string, unknown>;
}