import { Injectable, signal, type Signal } from '@angular/core';
import { type AuroraSession } from './session.types';

const STORAGE_KEY = 'aurora.session.v1';

/**
 * Typed wrapper over a single localStorage entry. All persisted SPA state
 * lives under one key so:
 *   - inspection in DevTools shows everything at a glance,
 *   - invalidation is atomic (bump `STORAGE_KEY` version to nuke all),
 *   - writes from different consumers don't clobber each other's keys.
 *
 * Concurrency model: every `set` reads the current in-memory snapshot,
 * merges, and writes back to both the signal and localStorage. The signal
 * is the in-memory source of truth — consumers should read from it
 * (directly or via `get(key)`) rather than going to localStorage themselves.
 */
@Injectable({ providedIn: 'root' })
export class SessionService {
  private readonly _state = signal<AuroraSession>(this.hydrate());

  /** Read-only view of the full session state for reactive consumers. */
  readonly state: Signal<AuroraSession> = this._state.asReadonly();

  /** Read a single key from the in-memory snapshot. */
  get<K extends keyof AuroraSession>(key: K): AuroraSession[K] | undefined {
    return this._state()[key];
  }

  /** Merge a key into the snapshot, update the signal, and persist. */
  set<K extends keyof AuroraSession>(key: K, value: AuroraSession[K]): void {
    const next: AuroraSession = { ...this._state(), [key]: value };
    this._state.set(next);
    this.persist(next);
  }

  /** Wipe everything. Used on logout or version migration. */
  clear(): void {
    this._state.set({});
    try {
      localStorage.removeItem(STORAGE_KEY);
    } catch {
      // localStorage unavailable — nothing to do.
    }
  }

  private hydrate(): AuroraSession {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      return raw ? (JSON.parse(raw) as AuroraSession) : {};
    } catch {
      // Corrupted entry or localStorage disabled — start fresh in memory.
      return {};
    }
  }

  private persist(state: AuroraSession): void {
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
    } catch {
      // Quota exceeded or localStorage disabled — degrade gracefully.
    }
  }
}
