import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';

/**
 * Service unifié de gestion du localStorage
 * Combine fonctionnalités de StorageService et StorageService
 */
@Injectable({
  providedIn: 'root',
})
export class StorageService implements Storage {
  private storage: Storage;
  private storageSub = new Subject<{ key: string; data: any }>();

  constructor() {
    // Initialisation directe avec localStorage
    this.storage = typeof window !== 'undefined' ? localStorage : this.createMockStorage();
  }

  // ========== Interface Storage ==========

  [name: string]: any;
  length: number = 0;

  clear(): void {
    this.storage.clear();
  }

  getItem(key: string): string | null {
    return this.storage.getItem(key);
  }

  key(index: number): string | null {
    return this.storage.key(index);
  }

  removeItem(key: string): void {
    this.storage.removeItem(key);
    this.storageSub.next({ key, data: null });
  }

  setItem(key: string, value: string): void {
    this.storage.setItem(key, value);
    this.storageSub.next({ key, data: value });
  }

  // ========== Méthodes étendues pour objets ==========

  /**
   * Récupère un objet depuis le localStorage
   */
  getObject<T>(key: string): T | null {
    const item = this.storage.getItem(key);
    if (!item) return null;
    try {
      return JSON.parse(item) as T;
    } catch {
      return null;
    }
  }

  /**
   * Stocke un objet dans le localStorage
   */
  setItemObject<T>(key: string, value: T): void {
    this.storage.setItem(key, JSON.stringify(value));
    this.storageSub.next({ key, data: value });
  }

  /**
   * Observable pour écouter les changements de storage
   */
  watchStorage(): Observable<{ key: string; data: any }> {
    return this.storageSub.asObservable();
  }

  // ========== Mock Storage pour SSR ==========

  private createMockStorage(): Storage {
    const mockData: { [key: string]: string } = {};
    return {
      length: 0,
      clear: () => {},
      getItem: (key: string) => mockData[key] || null,
      key: (index: number) => null,
      removeItem: (key: string) => delete mockData[key],
      setItem: (key: string, value: string) => (mockData[key] = value),
    };
  }
}
