import { inject, Type } from '@angular/core';
import { StorageProvider } from './storage-providers';
import { z } from 'zod';
import { hash } from './hash.utils';
import { USER_SUB } from './tokens';

export class Storage {
  #userSub = inject(USER_SUB);

  constructor(private storageProvider: StorageProvider) {}

  #getKey(token: string | object): string {
    const userSub = this.#userSub();
    return `${userSub}:${hash(token)}`;
  }

  set<T>(token: string | object, value: T): void {
    this.storageProvider.set(this.#getKey(token), value);
  }

  get<T>(token: string | object, schema?: z.ZodType<T>): T | unknown {
    const data = this.storageProvider.get(this.#getKey(token));
    if (schema) {
      return schema.parse(data);
    }
    return data;
  }

  clear(token: string | object): void {
    this.storageProvider.clear(this.#getKey(token));
  }
}

const storageMap = new WeakMap<Type<StorageProvider>, Storage>();

export function injectStorage(storageProvider: Type<StorageProvider>): Storage {
  if (storageMap.has(storageProvider)) {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    return storageMap.get(storageProvider)!;
  }

  const storage = new Storage(inject(storageProvider));
  storageMap.set(storageProvider, storage);
  return storage;
}
