import { AppNodeType, Group } from '../types/node';
import { saveCanvasStateToStorage } from './storage';
import { Edge } from '@xyflow/react';
import { logger } from '@/lib/utils/logger';

const log = logger.namespace('CanvasPersistence');

/**
 * Canvas Persistence Service
 * Handles auto-saving canvas state with debouncing and error handling
 */
export class CanvasPersistenceService {
  private saveTimeout: NodeJS.Timeout | null = null;
  private readonly SAVE_DELAY = 2000; // 2 seconds debounce
  private readonly MAX_RETRIES = 3;
  private retryCount = 0;
  private lastSaveAttempt: number = 0;
  private readonly MIN_SAVE_INTERVAL = 1000; // Minimum 1 second between saves
  
  private storageKey: string;
  private projectId?: string;
  
  constructor(storageKey: string, projectId?: string) {
    this.storageKey = storageKey;
    this.projectId = projectId;
  }
  
  /**
   * Update storage key and project ID
   */
  updateContext(storageKey: string, projectId?: string) {
    this.storageKey = storageKey;
    this.projectId = projectId;
  }
  
  /**
   * Schedule an auto-save with debouncing
   * Cancels previous pending saves and schedules a new one
   */
  scheduleSave(nodes: AppNodeType[], edges: Edge[], groups?: Group[]) {
    // Cancel any pending save
    if (this.saveTimeout) {
      clearTimeout(this.saveTimeout);
    }
    
    // Schedule new save
    this.saveTimeout = setTimeout(() => {
      this.executeSave(nodes, edges, groups);
    }, this.SAVE_DELAY);
  }
  
  /**
   * Execute immediate save (bypasses debounce)
   * Useful for critical operations like closing or switching canvas
   */
  async saveNow(nodes: AppNodeType[], edges: Edge[], groups?: Group[]): Promise<boolean> {
    // Cancel any pending debounced save
    if (this.saveTimeout) {
      clearTimeout(this.saveTimeout);
      this.saveTimeout = null;
    }
    
    return this.executeSave(nodes, edges, groups);
  }
  
  /**
   * Internal method to execute the save operation
   * Includes rate limiting, retry logic, and error handling
   */
  private async executeSave(nodes: AppNodeType[], edges: Edge[], groups?: Group[]): Promise<boolean> {
    const now = Date.now();
    
    // Rate limiting: prevent saves too close together
    if (now - this.lastSaveAttempt < this.MIN_SAVE_INTERVAL) {
      log.log('Save rate limited, scheduling retry');
      // Reschedule after minimum interval
      this.saveTimeout = setTimeout(() => {
        this.executeSave(nodes, edges, groups);
      }, this.MIN_SAVE_INTERVAL);
      return false;
    }
    
    this.lastSaveAttempt = now;
    
    try {
      const state = {
        nodes,
        edges,
        ...(groups && { groups })
      };
      
      await saveCanvasStateToStorage(this.storageKey, state, this.projectId);
      
      // Reset retry count on success
      this.retryCount = 0;
      
      log.log('Auto-save successful', {
        key: this.storageKey,
        nodeCount: nodes.length,
        edgeCount: edges.length,
      });
      
      return true;
    } catch (error) {
      log.error('Auto-save failed', error);
      
      // Retry logic with exponential backoff
      if (this.retryCount < this.MAX_RETRIES) {
        this.retryCount++;
        const retryDelay = Math.min(1000 * Math.pow(2, this.retryCount - 1), 10000);
        
        log.log(`Retrying save (${this.retryCount}/${this.MAX_RETRIES}) in ${retryDelay}ms`);
        
        this.saveTimeout = setTimeout(() => {
          this.executeSave(nodes, edges, groups);
        }, retryDelay);
      } else {
        log.error('Max retries reached, save failed permanently');
        this.retryCount = 0; // Reset for next attempt
        
        // Optionally notify user of save failure
        this.notifyUser('保存失败，请检查网络连接');
      }
      
      return false;
    }
  }
  
  /**
   * Cancel any pending saves
   */
  cancelPendingSave() {
    if (this.saveTimeout) {
      clearTimeout(this.saveTimeout);
      this.saveTimeout = null;
    }
  }
  
  /**
   * Cleanup method to be called when service is no longer needed
   */
  destroy() {
    this.cancelPendingSave();
  }
  
  /**
   * Notify user of save status (can be customized with toast/notification system)
   */
  private notifyUser(message: string) {
    // This can be replaced with a proper notification system
    // For now, just log to console
    log.warn(message);
    
    // Example: integrate with a toast notification system
    // toast.error(message);
  }
}

/**
 * Hook to use canvas persistence service
 * Automatically handles cleanup on unmount
 */
import { useEffect, useRef } from 'react';

export function useCanvasAutosave(
  storageKey: string,
  projectId: string | undefined,
  nodes: AppNodeType[],
  edges: Edge[],
  groups?: Group[]
) {
  const serviceRef = useRef<CanvasPersistenceService | null>(null);
  
  // Initialize service
  useEffect(() => {
    serviceRef.current = new CanvasPersistenceService(storageKey, projectId);
    
    return () => {
      // Cleanup on unmount
      serviceRef.current?.destroy();
    };
  }, [storageKey, projectId]);
  
  // Update context when storage key or project ID changes
  useEffect(() => {
    if (serviceRef.current) {
      serviceRef.current.updateContext(storageKey, projectId);
    }
  }, [storageKey, projectId]);
  
  // Schedule save when canvas state changes
  useEffect(() => {
    if (serviceRef.current && nodes.length > 0) {
      serviceRef.current.scheduleSave(nodes, edges, groups);
    }
  }, [nodes, edges, groups]);
  
  // Return service for manual save operations
  return {
    saveNow: () => serviceRef.current?.saveNow(nodes, edges, groups),
    cancelPendingSave: () => serviceRef.current?.cancelPendingSave(),
  };
}
