import { Arg, Mutation, Query, Resolver } from "@aet/gql-tools/macro"
import { InputPreferences, Preferences, defaultPreferences } from "~/shared/models/index"
import { broadcast } from "../utils"

const PREFS_KEY = "preferences"

@Resolver(() => Preferences)
export class PreferencesResolver {
  @Query()
  preferences(): Preferences {
    return PreferencesCache.cache.get()
  }

  @Mutation()
  setPreferences(@Arg() preferences: InputPreferences): Preferences {
    return PreferencesCache.cache.set(preferences)
  }
}

export class PreferencesCache {
  private data: Preferences
  private static _instance: PreferencesCache

  static get cache(): PreferencesCache {
    return (this._instance ??= new PreferencesCache())
  }

  constructor() {
    const text = localStorage.getItem(PREFS_KEY)!
    const prefs = new Preferences({ ...defaultPreferences })
    Object.assign(prefs, JSON.parse(text))
    this.data = prefs
  }

  get(): Preferences {
    return this.data
  }

  set(preferences: Partial<Preferences>): Preferences {
    Object.assign(this.data, stripUndefined(preferences))
    if ("enabled" in preferences) {
      broadcast()
    }
    localStorage.setItem(PREFS_KEY, JSON.stringify(this.data))
    return this.data
  }
}

export function getPreference<K extends keyof Preferences>(
  key: K,
): Preferences[K] | undefined {
  try {
    const text = localStorage.getItem(PREFS_KEY)!
    const prefs = JSON.parse(text)
    return prefs[key]
  } catch {}
}

function stripUndefined<T extends object>(obj: T): Partial<T> {
  return Object.fromEntries(
    Object.entries(obj).filter(([, value]) => value !== undefined),
  ) as T
}
