import { createApi } from '@reduxjs/toolkit/query/react'
import { createSlice, current } from "@reduxjs/toolkit";
import { gql } from 'graphql-request'
import { graphqlRequestBaseQuery } from '@rtk-query/graphql-request-base-query'; //npm install


const API_URL = "http://shop-roles.node.ed.asmer.org.ua/graphql";

const prepareHeaders = (headers, { getState }) => {
  // By default, if we have a token in the store, let's use that for authenticated requests
  const token = getState().auth?.token || null;
  if (token) {
    headers.set("Authorization", `Bearer ${token}`);
  }
  return headers;
}

export const api = createApi({
  reducerPath: 'api',
  baseQuery: graphqlRequestBaseQuery({
    url: API_URL,
    prepareHeaders
  }),
  tagTypes: ['Category', 'Order', 'Good'],
  endpoints: (builder) => ({
    getCategories: builder.query({
      query: () => ({
        document: gql`
                  query GetCategories{
                      CategoryFind(query: "[{\\"parent\\": null}]") {
                        _id name goods {
                          _id name
                        }, subCategories {
                          name
                        }
                      }
                    }
                  `}),
      providesTags: ['Category'],
    }),
    getCategoryById: builder.query({
      query: (_id) => ({
        document: gql`
                  query GetCategory($q: String) {
                      CategoryFindOne(query: $q) {
                        _id
                        name,
                        goods{
                          name,
                          _id,
                          images{
                            _id,
                            url
                          },
                          price
                        },
                        parent {
                          _id,
                          name
                        },
                        subCategories{
                          name,
                          _id
                          subCategories{
                            name,
                            _id
                          }
                        }
                      }
                  }
                  `,
        variables: { q: JSON.stringify([{ _id }]) }
      }),
    }),
    getGoodById: builder.query({
      query: (_id) => ({
        document: gql`
                  query GetGood($q: String) {
                    GoodFindOne(query: $q) {
                      _id,
                      name,
                      categories{
                        _id,
                        name
                      },
                      description,
                      price,
                      images{
                        _id,
                        url
                      }
                    }
                   }
                  `,
        variables: { q: JSON.stringify([{ _id }]) }
      }),
    }),
    getUserById: builder.query({
      query: (_id) => ({
        document: gql`
                    query GetUser($q: String) {
                        UserFindOne(query: $q) {
                            _id
                            login
                            nick
                            avatar { url }
                            acl
                        }
                    }
                `,
        variables: { q: JSON.stringify([{ _id }]) }
      }),
      providesTags: (result, error, id) => ([{ type: 'User', id }])
    }),
    getOwnerOrder: builder.query({
      query: ({ limit, skip }) => ({
        document: gql`
                  query orders($q: String) {
                    OrderFind(query: $q) {
                      _id, total, createdAt, owner{
                        _id, login
                      }, orderGoods{
                        price, count, good{
                          name, _id, images {
                            url
                          }
                        }
                      }
                    }
                  }
                  `,
        variables: { q: JSON.stringify([{}, { limit: [limit], skip: [skip] }]) }
      }),
      providesTags: ['Order'],
    }),
    getOrderCount: builder.query({
      query: () => ({
        document: gql`
                  query getOrderCount($q: String) {
                    OrderCount(query: $q)
                  }`,
        variables: { q: JSON.stringify([{}]) }
      })
    }),
    getOrderGood: builder.query({
      query: () => ({
        document: gql`
                  query orders($q: String) {
                    OrderGoodFind(query: $q) {
                      _id, createdAt, price, total, count, goodName, good {
                        _id, name
                      }, order {
                        _id, total, orderGoods {
                          count, good {
                            name
                          }
                        }
                      }, owner {
                        _id login
                      }
                    }
                  }
                  `,
        variables: { q: JSON.stringify([{}]) }
      })
    }),
    getGoods: builder.query({
      query: () => ({
        document: gql`
                  query GetGoods($q: String) {
                    GoodFind(query: $q) {
                      _id, name, description, price, categories {
                        _id, name
                      }
                    }
                  }`,
        variables: { q: JSON.stringify([{}]) }
      }),
      providesTags: ['Good'],
    }),
    getUserCount: builder.query({
      query: () => ({
        document: gql`
                  query GetUserCount($q: String) {
                    UserCount(query: $q)
                  }`,
        variables: { q: JSON.stringify([{}]) }
      })
    }),
    getUsers: builder.query({
      query: ({ skip, limit }) => ({
        document: gql`
                  query GetUsers($q: String) {
                    UserFind(query: $q) {
                      _id, login, createdAt
                    }
                  }`,
        variables: { q: JSON.stringify([{}, { skip: [skip], limit: [limit] }]) }
      })
    }),
    login: builder.mutation({
      query: ({ login, password }) => ({
        document: gql`
                  query login($login: String, $password: String) {
                      login(login: $login, password: $password) 
                  }
                  `,
        variables: { login, password }
      })
    }),
    register: builder.mutation({
      query: ({ login, password }) => ({
        document: gql`
                  mutation registration($login:String, $password: String) {
                      UserUpsert(user: {login:$login, password: $password}){
                           _id login createdAt
                        }
                  }`,
        variables: { login, password }
      })
    }),
    createOrder: builder.mutation({
      query: (orderGoods) => ({
        document: gql`
                mutation ordering($orderGoods: OrderInput) {
                  OrderUpsert(order: $orderGoods) {
                    _id, total, orderGoods {
                      good {
                        name, _id
                      }
                    }
                  }
                }`,
        variables: { orderGoods: { orderGoods } }
      }),
      invalidatesTags: ['Order'],
    }),
    createCategory: builder.mutation({
      query: (category) => ({
        document: gql`
                  mutation createCategory($category: CategoryInput) {
                    CategoryUpsert(category: $category) {
                      _id
                    }
                  }`,
        variables: { category }
      }),
      invalidatesTags: ['Category'],
    }),
    deleteCategory: builder.mutation({
      query: (category) => ({
        document: gql`
                  mutation deleteCategory($category: CategoryInput) {
                    CategoryDelete(category: $category) {
                      _id, name, goods {
                        name, _id
                      }
                    }
                  }`,
        variables: { category }
      }),
      invalidatesTags: ['Category'],
    }),
    createGood: builder.mutation({
      query: (good) => ({
        document: gql`
                  mutation createGood($good: GoodInput) {
                    GoodUpsert(good: $good) {
                      _id
                    }
                  }`,
        variables: { good }
      }),
      invalidatesTags: ['Good']
    }),
    deleteGood: builder.mutation({
      query: (good) => ({
        document: gql`
                  mutation deleteGood($good: GoodInput) {
                    GoodDelete(good: $good) {
                      _id, name, images {
                        url, _id
                      }, price, description
                    }
                  }`,
        variables: { good }
      }),
      invalidatesTags: ['Good']
    }),
  }),
});

export const createGood = good =>
  async dispatch => {
    await dispatch(api.endpoints.createGood.initiate(good));
  }



export const createCategory = category =>
  async dispatch => {
    await dispatch(api.endpoints.createCategory.initiate(category));
  }

export const deleteCategory = category =>
  async dispatch => {
    await dispatch(api.endpoints.deleteCategory.initiate(category));
  }

export const actionOrder = orderGoods =>
  async dispatch => {
    await dispatch(api.endpoints.createOrder.initiate(orderGoods));
    dispatch(cartSlice.actions.clearCart());
  }

function jwtDecode(token) {
  try {
    const tokenArr = token.split(".");
    const tokenJsonStr = atob(tokenArr[1]);
    const tokenJson = JSON.parse(tokenJsonStr);
    return tokenJson;
  }
  catch (error) { }
}
export const authSlice = createSlice({
  name: 'auth',
  initialState: {},
  reducers: {
    login(state, { payload }) {
      const tokenPayload = jwtDecode(payload);
      if (tokenPayload) {
        state.token = payload;
        state.payload = tokenPayload;
        state.error = false;
      }
    },
    logout() {
      return {};
    }
  },
  extraReducers: (builder) => {
    builder.addMatcher(
      api.endpoints.login.matchFulfilled,
      (state, { payload }) => {
        if (!payload.login) {
          state.error = true;
        }
      }
    )
  },
})

export const actionFullLogin = ({ login, password }) =>
  async (dispatch) => {
    const payload = await dispatch(api.endpoints.login.initiate({ login, password }))
    if (payload.data.login)
      dispatch(authSlice.actions.login(payload.data.login));
  }

export const actionFullRegister = (login, password) =>
  async dispatch => {
    const payload = await dispatch(api.endpoints.register.initiate(login, password));
    console.log(payload);
    dispatch(actionFullLogin(login, password));
  }

const getItemIndex = (state, idToFind) => {
  const idsArr = state.goods.map(item => item.good._id);
  return idsArr.indexOf(idToFind);
}
const initialState = {
  goods: [],
  totalAmount: 0,
  goodsCount: 0
}

function calculateTotalAmounts(state, currentState) {
  state.totalAmount = currentState.goods.reduce((totalAmount, item) => totalAmount + item.good.price * item.count, 0);
  state.goodsCount = currentState.goods.reduce((goodsCount, item) => goodsCount + item.count, 0);
}

export const cartSlice = createSlice({
  name: 'cart',
  initialState,
  reducers: {
    addGood(state, action) {
      const itemIndex = getItemIndex(state, action.payload.good._id);
      if (itemIndex && itemIndex < 0)
        state.goods.push(action.payload);
      else {
        state.goods[itemIndex].count += +action.payload.count;
      }
      calculateTotalAmounts(state, current(state));
    },
    decreaseGoodCount(state, action) {
      const itemIndex = getItemIndex(state, action.payload.good._id);
      if (state.goods[itemIndex].count > 1) {
        state.goods[itemIndex].count -= 1;
      }
      else {
        state.goods = state.goods.filter(item => item.good._id !== action.payload.good._id);
      }
      calculateTotalAmounts(state, current(state));
    },
    setGoodCount(state, action) {
      const itemIndex = getItemIndex(state, action.payload.good._id);
      state.goods[itemIndex].count = action.payload?.count;
      calculateTotalAmounts(state, current(state));
    },
    deleteGood(state, action) {
      state.goods = state.goods.filter(item => item.good._id !== action.payload.good._id);
      calculateTotalAmounts(state, current(state));
    },
    clearCart() {
      return initialState;
    }


  },
});
export const { addGood, deleteGood, decreaseGoodCount, setGoodCount, clearCart } = cartSlice.actions;
export const { useGetCategoriesQuery, useGetCategoryByIdQuery, useGetGoodByIdQuery, useLoginMutation, useGetOwnerOrderQuery,
  useRegisterMutation, useGetUserByIdQuery, useCreateCategoryMutation, useGetGoodsQuery, useGetUsersQuery, useGetOrderGoodQuery,
  useGetUserCountQuery, useGetOrderCountQuery } = api;
