// [REQ D3]  GraphQL z Apollo Client – ApolloClient + SchemaLink + makeExecutableSchema (in-memory)
// [REQ T5]  Obsługa zapytań API – QueryClient (React Query) + ApolloClient (GraphQL)
// [REQ T4]  Context API – ApolloProvider i QueryClientProvider opakowują całą aplikację
// StricMode jest potrzebny do wykrywania potencjalnych problemów przed zbudowaniem.
import { StrictMode } from 'react';
// createRoot odpowiada wczepienie w HTML
import { createRoot } from 'react-dom/client';
//QueryClient i QueryClientProvider są potrzebne do konfiguracji react-query - pamięc podręczna zapytań
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
//ApolloClient i InMemoryCache są potrzebne do konfiguracji Apollo Client - pamięc podręczna zapytań GraphQL
import { ApolloClient, InMemoryCache } from '@apollo/client/core';
// ApolloProvider jest potrzebny do klienta Apollo w całej aplikacji React
import { ApolloProvider } from '@apollo/client/react';
// SchemaLink jest potrzbeny do tworzenia klienta Apollo z lokalnym schematem GraphQL wewnątrz kodu
import { SchemaLink } from '@apollo/client/link/schema';
// makeExecutableSchema jest potrzebny do tworzenia szablonów za pomocą opisu GraphQL w kodzie
import { makeExecutableSchema } from '@graphql-tools/schema';
// Importowanie głównego komponentu aplikacji
import App from './App.jsx';

// Instancja z konfiguracją react-query
const queryClient = new QueryClient({
  defaultOptions: { queries: { staleTime: 1000 * 60 * 5, retry: 1 } },
});

// Definicja schematu GraphQL
const typeDefs = `
  type UserProfile {
    id: ID!
    name: String!
    email: String!
    role: String!
    joinedAt: String!
    reservationsCount: Int!
    avatarUrl: String!
  }

  type Review {
    id: ID!
    reservationId: String!
    serviceId: String!
    userId: String!
    userName: String!
    rating: Int!
    comment: String
    createdAt: String!
  }

  type Query {
    userProfile(id: ID!): UserProfile
    serviceReviews(serviceId: String!): [Review!]!
    userReviews(userId: String!): [Review!]!
  }

  type Mutation {
    submitReview(
      reservationId: String!
      serviceId: String!
      userId: String!
      userName: String!
      rating: Int!
      comment: String
    ): Review!
  }
`;
// Przechowywanie recenzji w pamięci (symulacja bazy danych)
const reviewStore = [
  { id: 'rv1', reservationId: 'r3', serviceId: 's3', userId: 'u4', userName: 'Marek Nowak',   rating: 5, comment: 'Excellent service!',        createdAt: '2026-05-10' },
  { id: 'rv2', reservationId: 'r5', serviceId: 's3', userId: 'u3', userName: 'Anna Kowalski', rating: 4, comment: 'Good experience overall.',    createdAt: '2026-06-02' },
  { id: 'rv3', reservationId: 'r6', serviceId: 's2', userId: 'u4', userName: 'Marek Nowak',   rating: 3, comment: 'Average, could be better.',   createdAt: '2026-06-05' },
];
// Zmienna do generowania unikalnych identyfikatorów recenzji
let nextReviewId = reviewStore.length + 1;

// Konfiguracja klienta Apollo z lokalnym schematem GraphQL
const apolloClient = new ApolloClient({
  // zmiast linku z internetu tworzymy lokalny schemat
  link: new SchemaLink({
    // makeExecutableSchema tworzy schemat GraphQL z definicji typów i resolverów w kodzie
    schema: makeExecutableSchema({
      // typeDefs definiuje wyżej strukturę danych i zapytań GraphQL
      typeDefs,
      //inline resolvers definiuje funkcje obsługujące zapytania i mutacje GraphQL w kodzie
      resolvers: {
        // Logika resolverów dla zapytań i mutacji GraphQL
        Query: {
          // Jeśli fronted pyta o profil użytkownika, zwracamy dane zdefiniowane w kodzie oraz url awatara
          userProfile: (_, { id }) => ({
            id,
            name: 'Anna Kowalski',
            email: 'anna.kowalski@example.com',
            role: 'client',
            joinedAt: '2024-01-15',
            reservationsCount: 3,
            avatarUrl: `https://i.pravatar.cc/150?u=${id}`,
          }),
          // Jeśli fronted pyta o recenzje dla danego serwisu, filtrujemy recenzje w pamięci według serviceId
          serviceReviews: (_, { serviceId }) => reviewStore.filter((r) => r.serviceId === serviceId),
          // Jeśli fronted pyta o recenzje danego użytkownika, filtrujemy recenzje w pamięci według userId
          userReviews:    (_, { userId })    => reviewStore.filter((r) => r.userId === userId),
        },
        // Logika resolverów dla mutacji GraphQL
        Mutation: {
          // Jeśli fronted wysyła mutację submitReview, tworzymy nową recenzję i dodajemy ją do pamięci
          submitReview: (_, args) => {
            // Tworzymy nową recenzję z unikalnym id, danymi z args oraz aktualną datą
            const review = { id: `rv${nextReviewId++}`, ...args, comment: args.comment ?? null, createdAt: new Date().toISOString().split('T')[0] };
            reviewStore.push(review);
            return review;
          },
        },
      },
    }),
  }),
  // Włączenie pamięci podręcznej w Apollo Client, aby przechowywać wyniki zapytań GraphQL
  cache: new InMemoryCache(),
});
// Renderowanie aplikacji React w elemencie root
createRoot(document.getElementById('root')).render(
  // StrictMode jest używany do wykrywania potencjalnych problemów w aplikacji React
  <StrictMode>
    {/* // ApolloProvider dostarcza klienta Apollo do całej aplikacji React, umożliwiając korzystanie z GraphQL */}
    <ApolloProvider client={apolloClient}>
      {/* // QueryClientProvider dostarcza klienta react-query do całej aplikacji */}
      <QueryClientProvider client={queryClient}>
        {/* // Renderowanie głównego komponentu aplikacji który otrzymuje wszystkie Contexty z "góry" */}
        <App />
      </QueryClientProvider>
    </ApolloProvider>
  </StrictMode>,
);
