
// API based storage to replace Local Storage for server-side persistence
const API_BASE = '/api/data';

// Request deduplication and short-term caching
const pendingRequests = new Map<string, Promise<any>>();
const cache = new Map<string, { data: any, timestamp: number }>();
const CACHE_TTL = 5000; // 5 seconds cache for read operations

const getHeaders = (extraHeaders: Record<string, string> = {}) => {
  const sessionId = localStorage.getItem('sessionId');
  const headers: Record<string, string> = { ...extraHeaders };
  if (sessionId) {
    headers['x-session-id'] = sessionId;
  }
  return headers;
};

export const storage = {
  get: async <T>(key: string, defaultValue: T): Promise<T> => {
    // 1. Check cache first
    const cached = cache.get(key);
    if (cached && (Date.now() - cached.timestamp < CACHE_TTL)) {
      return cached.data as T;
    }

    // 2. Check if a request for this key is already in progress
    if (pendingRequests.has(key)) {
      return pendingRequests.get(key);
    }

    const fetchPromise = (async () => {
      let retries = 0;
      const maxRetries = 2;
      
      while (retries <= maxRetries) {
        try {
          const controller = new AbortController();
          const timeoutId = setTimeout(() => {
            try {
              controller.abort(`Timeout after 30s`);
            } catch (e) {
              controller.abort();
            }
          }, 30000);

          const response = await fetch(`${API_BASE}/${key}`, {
            headers: getHeaders({ 'Accept': 'application/json' }),
            credentials: 'include',
            signal: controller.signal
          });
          clearTimeout(timeoutId);
          
          if (!response.ok) {
            throw new Error(`Failed to fetch ${key}: ${response.status} ${response.statusText}`);
          }
          
          const contentType = response.headers.get('content-type');
          if (!contentType || !contentType.includes('application/json')) {
            throw new Error(`Server returned non-JSON response for ${key}`);
          }
          
          const data = await response.json();
          // Update cache
          cache.set(key, { data, timestamp: Date.now() });
          return data;
        } catch (e: any) {
          if (e.name === 'AbortError') {
            console.warn(`[Storage] Fetch attempt ${retries + 1} timed out or aborted for ${key}`);
            retries++;
            if (retries <= maxRetries) {
              await new Promise(resolve => setTimeout(resolve, 1000 * retries));
              continue;
            }
          } else {
            console.error(`[Storage] Fetch error for ${key}:`, e.message || e);
          }
          throw e;
        }
      }
      throw new Error(`Failed to fetch ${key} after ${maxRetries} retries`);
    })();

    pendingRequests.set(key, fetchPromise);
    try {
      return await fetchPromise;
    } finally {
      pendingRequests.delete(key);
    }
  },
  set: async <T>(key: string, value: T): Promise<number | null> => {
    let retries = 0;
    const maxRetries = 2;

    while (retries <= maxRetries) {
      try {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => {
          try {
            controller.abort(`Timeout after 30s`);
          } catch (e) {
            controller.abort();
          }
        }, 30000);

        const response = await fetch(`${API_BASE}/${key}`, {
          method: 'POST',
          headers: getHeaders({ 'Content-Type': 'application/json' }),
          body: JSON.stringify(value),
          credentials: 'include',
          signal: controller.signal
        });
        clearTimeout(timeoutId);

        if (response.ok) {
          const data = await response.json();
          // Invalidate cache on successful write
          cache.delete(key);
          return data.lastChange || null;
        }
        
        let errorMessage = `Failed to save ${key}: ${response.status} ${response.statusText}`;
        try {
          const errorData = await response.json();
          if (errorData.error) errorMessage = errorData.error;
        } catch (e) {
          // Fallback to default message
        }
        
        if (response.status === 401) {
          console.error('Session expired or unauthorized');
        }
        throw new Error(errorMessage);
      } catch (e: any) {
        if (e.name === 'AbortError') {
          console.warn(`[Storage] Save attempt ${retries + 1} timed out or aborted for ${key}`);
          retries++;
          if (retries <= maxRetries) {
            await new Promise(resolve => setTimeout(resolve, 1000 * retries));
            continue;
          }
          throw new Error('SERVER_TIMEOUT');
        } else {
          console.error(`Error saving ${key}:`, e.message || e);
          throw e;
        }
      }
    }
    return null;
  },

  clearCache: (key?: string) => {
    if (key) {
      console.log(`[Storage] Clearing cache for key: ${key}`);
      cache.delete(key);
    } else {
      console.log('[Storage] Clearing all cache');
      cache.clear();
    }
  },
  
  // Auth helpers
  getUser: async () => {
    try {
      const response = await fetch('/api/auth/user', {
        headers: getHeaders(),
        credentials: 'include'
      });
      if (!response.ok) return null;
      return await response.json();
    } catch (e) {
      return null;
    }
  },
  setUser: async (user: any) => {
    try {
      const response = await fetch('/api/auth/user', {
        method: 'POST',
        headers: getHeaders({ 'Content-Type': 'application/json' }),
        body: JSON.stringify(user),
        credentials: 'include'
      });
      if (response.ok) {
        const data = await response.json();
        if (data.sessionId) {
          localStorage.setItem('sessionId', data.sessionId);
        }
      }
    } catch (e) {
      console.error('Error saving user:', e);
    }
  },
  logout: async () => {
    try {
      await fetch('/api/auth/logout', { 
        method: 'POST',
        headers: getHeaders(),
        credentials: 'include'
      });
      localStorage.removeItem('sessionId');
    } catch (e) {
      console.error('Error logging out:', e);
    }
  },
  
  // Data helpers
  getProjects: () => storage.get('projects', []),
  setProjects: (projects: any[]) => storage.set('projects', projects),
  
  getTasks: () => storage.get('tasks', []),
  setTasks: (tasks: any[]) => storage.set('tasks', tasks),
  
  getClients: () => storage.get('clients', []),
  setClients: (clients: any[]) => storage.set('clients', clients),
  
  getEngineers: () => storage.get('engineers', []),
  setEngineers: (engineers: any[]) => storage.set('engineers', engineers),
  
  getExpenses: () => storage.get('expenses', []),
  setExpenses: (expenses: any[]) => storage.set('expenses', expenses),
  
  getLeads: () => storage.get('leads', []),
  setLeads: (leads: any[]) => storage.set('leads', leads)
};
