// Funktionsprogrammierung in TypeScript - Kata Lösung

interface Entity {
  id: number;
}

interface User extends Entity {
  firstName: string;
  age: number;
  gender: 'male' | 'female';
  role: 'admin' | 'moderator' | 'user';
}

interface Product extends Entity {
  title: string;
  price: number;
}

const fetchData = async <T extends Entity>(
  apiUrl: string,
  key: string
): Promise<T[]> => {
  try {
    const response = await fetch(apiUrl);
    if (!response.ok) throw new Error('Fehler beim Abrufen der Daten');
    const data = await response.json();
    return data[key] || [];
  } catch (error) {
    console.error('API Fehler:', error);
    return [];
  }
};

class Store<T extends Entity> {
  private dataMap: Record<number, T> = {};

  save(data: T[]): void {
    this.dataMap = data.reduce((acc, item) => {
      acc[item.id] = item;
      return acc;
    }, {} as Record<number, T>);
  }

  filterBy(predicate: (item: T) => boolean): T[] {
    return Object.values(this.dataMap).filter(predicate);
  }
}

const createDataStore = <T extends Entity>() => {
  let dataMap: Record<number, T> = {};

  const save = (data: T[]): void => {
    dataMap = data.reduce((acc, item) => {
      acc[item.id] = item;
      return acc;
    }, {} as Record<number, T>);
  };

  const filterBy = (predicate: (item: T) => boolean): T[] => {
    return Object.values(dataMap).filter(predicate);
  };

  return { save, filterBy };
};

(async () => {
  const usersStore = new Store<User>();
  const productsStore = new Store<Product>();

  // const usersStore = createDataStore<User>();
  // const productsStore = createDataStore<Product>();

  const users = await fetchData<User>('https://dummyjson.com/users', 'users');
  usersStore.save(users);

  const products = await fetchData<Product>(
    'https://dummyjson.com/products',
    'products'
  );
  productsStore.save(products);

  const mapUser = (user: User) => ({ name: user.firstName, role: user.role });

  console.log(
    'Administratoren:',
    usersStore.filterBy((user) => user.role === 'admin').map(mapUser)
  );
  console.log(
    'Moderatoren:',
    usersStore.filterBy((user) => user.role === 'moderator').map(mapUser)
  );
  console.log(
    'Normale Benutzer:',
    usersStore.filterBy((user) => user.role === 'user').map(mapUser)
  );

  //   console.log(
  //   'Günstige Produkte:',
  //   productsStore.filterBy((product) => product.price < 50)
  // );
})();
