import { createAppSlice } from '../../app/createAppSlice';
import type { Book, InputBook } from './Book';

export type BooksSliceState = {
  books: Book[];
  status: 'idle' | 'loading' | 'failed';
  removeStatus: 'idle' | 'loading' | 'failed';
  saveStatus: 'idle' | 'loading' | 'failed';
};

export const booksSlice = createAppSlice({
  name: 'books',
  initialState: {
    books: [],
    status: 'idle',
    removeStatus: 'idle',
    saveStatus: 'idle',
  } as BooksSliceState,
  reducers: (create) => ({
    remove: create.asyncThunk(
      async (id: number) => {
        const response = await fetch(`http://localhost:3001/books/${id}`, {
          method: 'DELETE',
        });
        if (!response.ok) {
          throw new Error('Failed to delete book');
        }
        return id;
      },
      {
        pending: (state) => {
          state.removeStatus = 'loading';
        },
        fulfilled: (state, action) => {
          state.removeStatus = 'idle';
          state.books = state.books.filter(
            (book) => book.id !== action.payload,
          );
        },
        rejected: (state) => {
          state.removeStatus = 'failed';
        },
      },
    ),
    save: create.asyncThunk(
      async (book: InputBook) => {
        let url = 'http://localhost:3001/books';
        let method = 'POST';
        if (book.id) {
          url += `/${book.id}`;
          method = 'PUT';
        }

        const response = await fetch(url, {
          method,
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify(book),
        });
        if (response.ok) {
          const data = await response.json();
          return data;
        }
      },
      {
        pending: (state) => {
          state.saveStatus = 'loading';
        },
        fulfilled: (state, action) => {
          state.saveStatus = 'idle';
          const index = state.books.findIndex(
            (b) => b.id === action.payload.id,
          );
          if (index >= 0) {
            state.books[index] = action.payload;
          } else {
            state.books.push(action.payload);
          }
        },
        rejected: (state) => {
          state.saveStatus = 'failed';
        },
      },
    ),
    loadData: create.asyncThunk(
      async () => {
        const response = await fetch('http://localhost:3001/books');
        if (!response.ok) {
          throw new Error('Failed to load books data');
        }
        return response.json();
      },
      {
        pending: (state) => {
          state.status = 'loading';
        },
        fulfilled: (state, action) => {
          state.status = 'idle';
          state.books = action.payload;
        },
        rejected: (state) => {
          state.status = 'failed';
        },
      },
    ),
  }),
  selectors: {
    selectAllBooks: (state) => state.books,
    selectBookById: (state) => (id: number) =>
      state.books.find((b) => b.id === id),
    selectStatus: (state) => state.status,
    selectRemoveStatus: (state) => state.removeStatus,
    selectSaveStatus: (state) => state.saveStatus,
  },
});

export const {
  selectAllBooks,
  selectBookById,
  selectStatus,
  selectRemoveStatus,
  selectSaveStatus,
} = booksSlice.selectors;
export const { remove, save, loadData } = booksSlice.actions;
