import React from 'react';
import { TLUserPreferences, TLUser } from '@tldraw/tldraw';
import { Session } from '@supabase/supabase-js';
import { CCUser } from '../../services/auth/authService';
import { logger } from '../../debugConfig';

// Type-safe storage keys
export enum StorageKeys {
  USER = 'user',
  USER_ROLE = 'user_role',
  SUPABASE_TOKEN = 'supabase_token',
  SUPABASE_SESSION = 'supabase_session',
  MS_TOKEN = 'msAccessToken',
  NEO4J_USER_DB = 'neo4jUserDbName',
  NEO4J_WORKER_DB = 'neo4jWorkerDbName',
  USER_NODES = 'userNodes',
  CALENDAR_DATA = 'calendarData',
  IS_NEW_REGISTRATION = 'isNewRegistration',
  TLDRAW_PREFERENCES = 'tldrawUserPreferences',
  TLDRAW_FILE_PATH = 'tldrawUserFilePath',
  LOCAL_SNAPSHOT = 'localSnapshot',
  NODE_FILE_PATH = 'nodeFilePath',
  ONENOTE_NOTEBOOK = 'oneNoteNotebook',
  PRESENTATION_MODE = 'presentationMode',
  TLDRAW_USER = 'tldrawUser'
}

interface StorageValueTypes {
  [StorageKeys.USER]: CCUser;
  [StorageKeys.USER_ROLE]: string;
  [StorageKeys.SUPABASE_TOKEN]: string;
  [StorageKeys.SUPABASE_SESSION]: Session;
  [StorageKeys.MS_TOKEN]: string;
  [StorageKeys.NEO4J_USER_DB]: string;
  [StorageKeys.NEO4J_WORKER_DB]: string;
  [StorageKeys.USER_NODES]: any[];
  [StorageKeys.CALENDAR_DATA]: any;
  [StorageKeys.IS_NEW_REGISTRATION]: boolean;
  [StorageKeys.TLDRAW_PREFERENCES]: TLUserPreferences;
  [StorageKeys.TLDRAW_FILE_PATH]: string;
  [StorageKeys.LOCAL_SNAPSHOT]: any;
  [StorageKeys.NODE_FILE_PATH]: string;
  [StorageKeys.ONENOTE_NOTEBOOK]: any;
  [StorageKeys.PRESENTATION_MODE]: boolean;
  [StorageKeys.TLDRAW_USER]: TLUser;
}

type StorageKey = keyof StorageValueTypes;

class StorageService {
  private static instance: StorageService;

  private constructor() {}

  static getInstance(): StorageService {
    if (!StorageService.instance) {
      StorageService.instance = new StorageService();
    }
    return StorageService.instance;
  }

  get<K extends StorageKey>(key: K): StorageValueTypes[K] | null {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : null;
    } catch (error) {
      logger.error('storage-service', `Error retrieving ${key}:`, error);
      return null;
    }
  }

  set<K extends StorageKey>(key: K, value: StorageValueTypes[K]): void {
    try {
      const serializedValue = JSON.stringify(value);
      localStorage.setItem(key, serializedValue);
      logger.debug('storage-service', `Stored ${key} in localStorage`);
    } catch (error) {
      logger.error('storage-service', `Error storing ${key}:`, error);
    }
  }

  remove(key: StorageKey): void {
    try {
      localStorage.removeItem(key);
      logger.debug('storage-service', `Removed ${key} from localStorage`);
    } catch (error) {
      logger.error('storage-service', `Error removing ${key}:`, error);
    }
  }

  clearAll(): void {
    try {
      // Only clear app-specific storage, not Supabase's internal keys
      Object.values(StorageKeys).forEach(key => {
        localStorage.removeItem(key);
      });
      logger.debug('storage-service', 'Cleared all app items from localStorage');
    } catch (error) {
      logger.error('storage-service', 'Error clearing storage:', error);
    }
  }

  // Helper method to update state and storage together
  setStateAndStorage<K extends StorageKey>(
    setter: React.Dispatch<React.SetStateAction<StorageValueTypes[K]>>, 
    key: K, 
    value: StorageValueTypes[K]
  ): void {
    setter(value);
    this.set(key, value);
  }
}

export const storageService = StorageService.getInstance();
