import { useEffect, useMemo, useReducer, type ActionDispatch } from 'react';
import type { Book } from './Book';

type Action =
  | { type: 'LOAD' }
  | { type: 'LOAD_SUCCESS'; payload: Book[] }
  | { type: 'RATE'; payload: { id: number; rating: number } }
  | { type: 'RATE_SUCCESS'; payload: Book };

function middleware(dispatch: ActionDispatch<[action: Action]>) {
  return async function (action: Action) {
    switch (action.type) {
      case 'LOAD':
        const loadResponse = await fetch(
          `${import.meta.env.VITE_API_SERVER}/books`
        );
        const books = await loadResponse.json();
        dispatch({ type: 'LOAD_SUCCESS', payload: books });
        break;
      case 'RATE':
        const rateResponse = await fetch(
          `${import.meta.env.VITE_API_SERVER}/books/${action.payload.id}`,
          {
            method: 'PUT',
            headers: { 'Content-Type': 'Application/JSON' },
            body: JSON.stringify(action.payload),
          }
        );
        const updatedBook = await rateResponse.json();
        dispatch({
          type: 'RATE_SUCCESS',
          payload: updatedBook,
        });
        break;
    }
  };
}

function reducer(state: Book[], action: Action) {
  switch (action.type) {
    case 'LOAD_SUCCESS':
      return action.payload;
    case 'RATE_SUCCESS':
      return state.map((book) =>
        book.id === action.payload.id
          ? { ...book, rating: action.payload.rating }
          : book
      );
    default:
      return state;
  }
}

const BooksList: React.FC = () => {
  const [books, dispatch] = useReducer(reducer, []);

  const middlewareDispatch = useMemo(() => middleware(dispatch), [dispatch]);

  useEffect(() => {
    middlewareDispatch({ type: 'LOAD' });
  }, [middlewareDispatch]);

  return (
    <table>
      <thead>
        <tr>
          <th>Titel</th>
          <th>Autor</th>
          <th>ISBN</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        {books.map((book) => (
          <tr key={book.id}>
            <td>{book.title}</td>
            <td>{book.author}</td>
            <td>{book.isbn}</td>
            <td>
              {new Array(5).fill('').map((_, i) => (
                <button
                  className="ratingButton"
                  key={i}
                  onClick={() =>
                    middlewareDispatch({
                      type: 'RATE',
                      payload: { ...book, rating: i + 1 },
                    })
                  }
                >
                  {book.rating < i + 1 ? '\u2606' : '\u2605'}
                </button>
              ))}
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
};

export default BooksList;
