import * as fs from "fs";
import * as path from "path";

/**
 * Interface for sync progress state
 * Tracks the progress of batch sync operations
 */
export interface SyncProgressState {
  lastSyncedIndex: number;
  totalProfiles: number;
  startTime: number;
  lastUpdate: number;
  failedProfiles: Array<{ index: number; profileId: string; error: string }>;
  profileIds: string[]; // Track order of profile IDs for resume
}

/**
 * SyncProgressManager
 * Manages persistent storage of sync progress state
 * Enables resuming from checkpoints after failures
 */
export class SyncProgressManager {
  private static readonly FILE_PATH = ".sync-progress.json";

  /**
   * Save progress state to file
   * @param state - Current progress state to save
   */
  static save(state: SyncProgressState): void {
    try {
      const filePath = path.resolve(process.cwd(), this.FILE_PATH);
      state.lastUpdate = Date.now();
      fs.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
    } catch (error) {
      console.error("[SyncProgressManager] Error saving progress:", error);
    }
  }

  /**
   * Load progress state from file
   * @returns Progress state if exists, null otherwise
   */
  static load(): SyncProgressState | null {
    try {
      const filePath = path.resolve(process.cwd(), this.FILE_PATH);
      if (!fs.existsSync(filePath)) {
        return null;
      }

      const data = fs.readFileSync(filePath, "utf-8");
      const state = JSON.parse(data) as SyncProgressState;

      // Validate required fields
      if (
        typeof state.lastSyncedIndex !== "number" ||
        typeof state.totalProfiles !== "number" ||
        !Array.isArray(state.failedProfiles) ||
        !Array.isArray(state.profileIds)
      ) {
        console.warn("[SyncProgressManager] Invalid progress file, starting fresh");
        return null;
      }

      return state;
    } catch (error) {
      console.error("[SyncProgressManager] Error loading progress:", error);
      return null;
    }
  }

  /**
   * Clear progress file
   * Called on successful completion or when starting fresh
   */
  static clear(): void {
    try {
      const filePath = path.resolve(process.cwd(), this.FILE_PATH);
      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
        console.log("[SyncProgressManager] Progress file cleared");
      }
    } catch (error) {
      console.error("[SyncProgressManager] Error clearing progress:", error);
    }
  }

  /**
   * Get progress percentage
   * @param state - Current progress state
   * @returns Percentage complete (0-100)
   */
  static getProgressPercent(state: SyncProgressState): number {
    if (state.totalProfiles === 0) return 0;
    return Math.round((state.lastSyncedIndex / state.totalProfiles) * 100);
  }

  /**
   * Format elapsed time as readable string
   * @param startTime - Start timestamp in milliseconds
   * @returns Formatted time string (e.g., "2h 30m 15s")
   */
  static formatElapsedTime(startTime: number): string {
    const elapsed = Date.now() - startTime;
    const seconds = Math.floor(elapsed / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);

    const parts: string[] = [];
    if (hours > 0) parts.push(`${hours}h`);
    if (minutes % 60 > 0) parts.push(`${minutes % 60}m`);
    if (seconds % 60 > 0 || parts.length === 0) parts.push(`${seconds % 60}s`);

    return parts.join(" ");
  }

  /**
   * Log current progress to console
   * @param state - Current progress state
   */
  static logProgress(state: SyncProgressState): void {
    const percent = this.getProgressPercent(state);
    const elapsed = this.formatElapsedTime(state.startTime);
    const failed = state.failedProfiles.length;

    console.log(
      `[Sync Progress] ${percent}% (${state.lastSyncedIndex}/${state.totalProfiles}) | Elapsed: ${elapsed} | Failed: ${failed}`,
    );
  }

  /**
   * Add failed profile to state
   * @param state - Progress state to update
   * @param index - Profile index
   * @param profileId - Profile ID that failed
   * @param error - Error message
   */
  static addFailedProfile(
    state: SyncProgressState,
    index: number,
    profileId: string,
    error: string,
  ): void {
    state.failedProfiles.push({ index, profileId, error });
    this.save(state);
  }

  /**
   * Initialize new progress state
   * @param profileIds - Array of profile IDs to sync
   * @returns New progress state
   */
  static initialize(profileIds: string[]): SyncProgressState {
    return {
      lastSyncedIndex: 0,
      totalProfiles: profileIds.length,
      startTime: Date.now(),
      lastUpdate: Date.now(),
      failedProfiles: [],
      profileIds,
    };
  }
}
