import type { ImagePack, QuickEntry } from './types';

export type DisabledPackImages = Record<string, string[]>;

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

function setOwn<T>(record: Record<string, T>, key: string, value: T): void {
  Object.defineProperty(record, key, {
    configurable: true,
    enumerable: true,
    value,
    writable: true
  });
}

function hasOwn(record: object, key: string): boolean {
  return Object.prototype.hasOwnProperty.call(record, key);
}

export function parseDisabledPackImages(raw: unknown): DisabledPackImages {
  if (!isRecord(raw) || !isRecord(raw['disabled'])) return {};
  const disabled: DisabledPackImages = {};
  for (const [packId, rawShortcodes] of Object.entries(raw['disabled'])) {
    if (!Array.isArray(rawShortcodes)) continue;
    const seen = new Set<string>();
    const shortcodes = rawShortcodes.filter((value): value is string => {
      if (typeof value !== 'string' || value.length === 0 || seen.has(value)) return false;
      seen.add(value);
      return true;
    });
    if (shortcodes.length > 0) setOwn(disabled, packId, shortcodes);
  }
  return disabled;
}

export function imageEnabled(disabled: DisabledPackImages, packId: string, shortcode: string): boolean {
  return !hasOwn(disabled, packId) || !disabled[packId].includes(shortcode);
}

export function withImageEnabled(
  disabled: DisabledPackImages,
  packId: string,
  shortcode: string,
  enabled: boolean
): DisabledPackImages {
  const current = hasOwn(disabled, packId) ? disabled[packId] : [];
  const nextShortcodes = enabled
    ? current.filter((item) => item !== shortcode)
    : current.includes(shortcode) ? [...current] : [...current, shortcode];
  if (nextShortcodes.length === current.length && nextShortcodes.every((item, index) => item === current[index])) {
    return disabled;
  }
  const next = { ...disabled };
  if (nextShortcodes.length === 0) delete next[packId];
  else setOwn(next, packId, nextShortcodes);
  return next;
}

export function enabledPacks(packs: ImagePack[], disabled: DisabledPackImages): ImagePack[] {
  return packs.map((pack) => ({
    ...pack,
    images: pack.images.filter((image) => imageEnabled(disabled, pack.id, image.shortcode))
  }));
}

export function enabledQuickReactions(
  quick: QuickEntry[],
  packs: ImagePack[],
  disabled: DisabledPackImages
): QuickEntry[] {
  const hidden = new Set<string>();
  const enabled = new Set<string>();
  for (const pack of packs) {
    for (const image of pack.images) {
      (imageEnabled(disabled, pack.id, image.shortcode) ? enabled : hidden).add(image.reaction_key);
    }
  }
  return quick.filter((entry) => 'separator' in entry || !hidden.has(entry.key) || enabled.has(entry.key));
}
