import type { StorageService } from "../types";

function nsKey(namespace: string, key: string): string {
  return `architools:${namespace}:${key}`;
}

function nsPrefix(namespace: string): string {
  return `architools:${namespace}:`;
}

export class LocalStorageAdapter implements StorageService {
  async get<T>(namespace: string, key: string): Promise<T | null> {
    if (typeof window === "undefined") return null;
    try {
      const raw = window.localStorage.getItem(nsKey(namespace, key));
      if (raw === null) return null;
      return JSON.parse(raw) as T;
    } catch {
      return null;
    }
  }

  async set<T>(namespace: string, key: string, value: T): Promise<void> {
    if (typeof window === "undefined") return;
    window.localStorage.setItem(nsKey(namespace, key), JSON.stringify(value));
  }

  async delete(namespace: string, key: string): Promise<void> {
    if (typeof window === "undefined") return;
    window.localStorage.removeItem(nsKey(namespace, key));
  }

  async list(namespace: string): Promise<string[]> {
    if (typeof window === "undefined") return [];
    const prefix = nsPrefix(namespace);
    const keys: string[] = [];
    for (let i = 0; i < window.localStorage.length; i++) {
      const k = window.localStorage.key(i);
      if (k && k.startsWith(prefix)) {
        keys.push(k.slice(prefix.length));
      }
    }
    return keys;
  }

  async query<T>(
    namespace: string,
    predicate: (item: T) => boolean,
  ): Promise<T[]> {
    const keys = await this.list(namespace);
    const results: T[] = [];
    for (const key of keys) {
      const item = await this.get<T>(namespace, key);
      if (item !== null && predicate(item)) {
        results.push(item);
      }
    }
    return results;
  }

  async clear(namespace: string): Promise<void> {
    if (typeof window === "undefined") return;
    const keys = await this.list(namespace);
    for (const key of keys) {
      window.localStorage.removeItem(nsKey(namespace, key));
    }
  }

  async export(
    namespace: string,
    _options?: { lightweight?: boolean },
  ): Promise<Record<string, unknown>> {
    const keys = await this.list(namespace);
    const data: Record<string, unknown> = {};
    for (const key of keys) {
      data[key] = await this.get(namespace, key);
    }
    return data;
  }

  async import(
    namespace: string,
    data: Record<string, unknown>,
  ): Promise<void> {
    for (const [key, value] of Object.entries(data)) {
      await this.set(namespace, key, value);
    }
  }
}
