import { isSyncEnabled, setSyncEnabled, getLastSyncTime, setLastSyncTime, initSyncSettings } from './sync/syncSettings';
import { uploadTransactions, downloadTransactions, deleteTransactionFromServer } from './sync/transactionSync';
import { uploadBudgets, downloadBudgets } from './sync/budget';
import { clearCloudData } from './sync/clearCloudData';
import { 
  checkNetworkStatus, 
  getNetworkStatus, 
  setNetworkStatus, 
  startNetworkMonitoring, 
  stopNetworkMonitoring,
  withRetry,
  addToSyncQueue,
  processPendingSyncQueue,
  onNetworkStatusChange,
  NetworkStatus,
  RetryOptions
} from './networkUtils';

// Export all utility functions to maintain the same public API
export {
  isSyncEnabled,
  setSyncEnabled,
  uploadTransactions,
  downloadTransactions,
  deleteTransactionFromServer,
  uploadBudgets,
  downloadBudgets,
  getLastSyncTime,
  setLastSyncTime,
  initSyncSettings,
  clearCloudData,
  // 네트워크 관련 함수 추가 내보내기
  checkNetworkStatus,
  getNetworkStatus,
  startNetworkMonitoring,
  stopNetworkMonitoring,
  onNetworkStatusChange
};

/**
 * 동기화 상태 인터페이스
 */
export interface SyncState {
  isEnabled: boolean;
  lastSyncTime: string | null;
  networkStatus: NetworkStatus;
  isSyncing: boolean;
  error: string | null;
}

// 현재 동기화 상태
let syncState: SyncState = {
  isEnabled: false,
  lastSyncTime: null,
  networkStatus: 'online',
  isSyncing: false,
  error: null
};

/**
 * 동기화 상태 초기화
 */
export const initSyncState = async (): Promise<void> => {
  syncState = {
    isEnabled: isSyncEnabled(),
    lastSyncTime: getLastSyncTime(),
    networkStatus: getNetworkStatus(),
    isSyncing: false,
    error: null
  };
  
  // 네트워크 모니터링 시작
  startNetworkMonitoring();
  
  // 네트워크 상태 변경 리스너 등록
  onNetworkStatusChange((status) => {
    syncState.networkStatus = status;
    // 상태 변경 이벤트 발생
    window.dispatchEvent(new CustomEvent('syncStateChange', { detail: { ...syncState } }));
    
    // 온라인 상태로 변경되면 보류 중인 동기화 작업 처리
    if (status === 'online') {
      processPendingSyncQueue();
      console.log('[네트워크 상태 변경] 온라인 상태로 변경되었습니다.');
    } else {
      console.log('[네트워크 상태 변경] 오프라인 상태로 변경되었습니다.');
    }
  });
  
  console.log('[동기화] 상태 초기화 완료', syncState);
};

/**
 * 현재 동기화 상태 가져오기
 */
export const getSyncState = (): SyncState => {
  return { ...syncState };
};

/**
 * 동기화 상태 업데이트
 */
const updateSyncState = (updates: Partial<SyncState>): void => {
  syncState = { ...syncState, ...updates };
  // 상태 변경 이벤트 발생
  window.dispatchEvent(new CustomEvent('syncStateChange', { detail: { ...syncState } }));
};

/**
 * 동기화 상태 변경 이벤트 리스너 등록
 */
export const onSyncStateChange = (callback: (state: SyncState) => void): () => void => {
  const handler = (event: Event) => {
    const customEvent = event as CustomEvent<SyncState>;
    callback(customEvent.detail);
  };
  
  window.addEventListener('syncStateChange', handler);
  
  // 구독 해제 함수 반환
  return () => {
    window.removeEventListener('syncStateChange', handler);
  };
};

/**
 * Synchronize all data with Supabase
 */
export const syncAllData = async (userId: string): Promise<void> => {
  if (!userId || !isSyncEnabled()) return;
  
  // 네트워크 상태 확인
  const isOnline = await checkNetworkStatus();
  if (!isOnline) {
    const error = new Error('오프라인 상태에서 동기화할 수 없습니다.');
    console.error('[동기화] 오류:', error);
    updateSyncState({ error: error.message });
    throw error;
  }
  
  // 동기화 상태 업데이트
  updateSyncState({ isSyncing: true, error: null });
  
  try {
    console.log('[동기화] 데이터 동기화 시작...');
    
    // 기존 동기화 순서: 서버에서 먼저 다운로드 후, 로컬 데이터 업로드
    // 이 순서를 유지하여 서버에 저장된 데이터를 먼저 가져온 후, 로컬 변경사항을 반영
    
    // 1. 서버에서 데이터 다운로드 (기존 데이터 불러오기)
    await withRetry(
      () => downloadTransactions(userId),
      { entityType: '트랜잭션 다운로드' }
    );
    
    await withRetry(
      () => downloadBudgets(userId),
      { entityType: '예산 다운로드' }
    );
    
    // 약간의 딜레이를 추가하여 다운로드된 데이터가 처리될 시간을 줌
    await new Promise(resolve => setTimeout(resolve, 500));
    
    // 2. 로컬 데이터를 서버에 업로드 (변경사항 반영)
    await withRetry(
      () => uploadTransactions(userId),
      { entityType: '트랜잭션 업로드' }
    );
    
    await withRetry(
      () => uploadBudgets(userId),
      { entityType: '예산 업로드' }
    );
    
    // 동기화 시간 업데이트
    setLastSyncTime();
    updateSyncState({ 
      lastSyncTime: getLastSyncTime(),
      isSyncing: false
    });
    
    console.log('[동기화] 데이터 동기화 완료!');
  } catch (error) {
    console.error('[동기화] 오류 발생:', error);
    updateSyncState({ 
      isSyncing: false, 
      error: error instanceof Error ? error.message : '알 수 없는 오류'
    });
    throw error; // 오류를 상위 호출자에게 전달하여 적절히 처리하도록 함
  }
};

// 동기화 결과를 위한 인터페이스 정의
export interface SyncResult {
  success: boolean;
  partial?: boolean;
  downloadSuccess?: boolean;
  uploadSuccess?: boolean;
  error?: Error | string | unknown;
}

// 안전하게 동기화 시도하는 함수 개선
export const trySyncAllData = async (userId: string): Promise<SyncResult> => {
  if (!userId || !isSyncEnabled()) return { success: true };
  
  // 네트워크 상태 확인
  const isOnline = await checkNetworkStatus();
  if (!isOnline) {
    const errorMsg = '오프라인 상태에서 동기화할 수 없습니다.';
    console.log('[동기화] 경고:', errorMsg);
    updateSyncState({ error: errorMsg });
    return { 
      success: false, 
      error: errorMsg 
    };
  }
  
  // 동기화 상태 업데이트
  updateSyncState({ isSyncing: true, error: null });
  
  let downloadSuccess = false;
  let uploadSuccess = false;
  let error = null;
  
  try {
    console.log('[동기화] 안전한 데이터 동기화 시도...');
    
    try {
      // 1단계: 서버에서 데이터 다운로드
      await withRetry(
        () => downloadTransactions(userId),
        { entityType: '트랜잭션 다운로드', maxRetries: 2 }
      );
      
      await withRetry(
        () => downloadBudgets(userId),
        { entityType: '예산 다운로드', maxRetries: 2 }
      );
      
      console.log('[동기화] 서버 데이터 다운로드 성공');
      downloadSuccess = true;
      
      // 다운로드 단계가 성공적으로 완료되면 부분 동기화 마킹
      setLastSyncTime('부분-다운로드');
      updateSyncState({ lastSyncTime: getLastSyncTime() });
    } catch (downloadError) {
      console.error('[동기화] 다운로드 오류:', downloadError);
      error = downloadError;
      // 다운로드 실패해도 업로드는 시도 - 부분 동기화
    }
    
    // 다운로드 후 약간의 지연을 추가하여 로컬 상태가 업데이트될 시간을 줌
    await new Promise(resolve => setTimeout(resolve, 500));
    
    try {
      // 2단계: 로컬 데이터를 서버에 업로드
      await withRetry(
        () => uploadTransactions(userId),
        { entityType: '트랜잭션 업로드', maxRetries: 2 }
      );
      
      await withRetry(
        () => uploadBudgets(userId),
        { entityType: '예산 업로드', maxRetries: 2 }
      );
      
      console.log('[동기화] 로컬 데이터 업로드 성공');
      uploadSuccess = true;
      
      // 업로드까지 성공적으로 완료되면 동기화 시간 업데이트
      setLastSyncTime();
      updateSyncState({ lastSyncTime: getLastSyncTime() });
    } catch (uploadError) {
      console.error('[동기화] 업로드 오류:', uploadError);
      if (!error) error = uploadError; // 다운로드에서 오류가 없었을 경우에만 설정
    }
    
    // 동기화 상태 업데이트
    updateSyncState({ isSyncing: false });
    
    // 결과 반환
    const success = downloadSuccess && uploadSuccess;
    const partial = (downloadSuccess || uploadSuccess) && !(downloadSuccess && uploadSuccess);
    
    if (!success && error) {
      updateSyncState({ 
        error: error instanceof Error ? error.message : '알 수 없는 오류'
      });
    }
    
    return {
      success,
      partial,
      downloadSuccess,
      uploadSuccess,
      error: error ? (error instanceof Error ? error.message : error) : undefined
    };
  } catch (generalError) {
    console.error('[동기화] 일반 오류:', generalError);
    updateSyncState({ 
      isSyncing: false, 
      error: generalError instanceof Error ? generalError.message : '알 수 없는 오류'
    });
    
    return {
      success: false,
      error: generalError
    };
  }
};

/**
 * 오프라인 모드에서 작업 큐에 추가하는 함수
 */
export const queueSyncOperation = (
  type: 'upload' | 'download' | 'delete',
  entityType: 'transaction' | 'budget' | 'categoryBudget',
  data: Record<string, unknown>
): void => {
  addToSyncQueue({ type, entityType, data });
  console.log(`[동기화] 작업 큐에 추가: ${type} ${entityType}`);
};

/**
 * 동기화 시스템 종료
 */
export const shutdownSyncSystem = (): void => {
  stopNetworkMonitoring();
  console.log('[동기화] 시스템 종료');
};
