import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { deleteMixdown, getJamTrack, createMixdown, enqueueMixdown } from '../../helpers/rest';
import { SAMPLE_RATE } from '../../helpers/jamTracks';

const initialState = {
  jamTrack: null,
  mixdowns: [],
  awaitingMixdown: null,
  enqueuedMixdown: null,
  enqueuedMixdowns: [],
  watchedMixdowns: [],
  jamTrackLoadingStatus: 'idle',
  mixdownsLoadingStatus: 'idle',
  deleteMixdownStatus: 'idle',
  newMixdownLoadingStatus: 'idle',
  error: null
};

export const fetchJamTrack = createAsyncThunk('jamTracks/fetchJamTrack', async (options, thunkAPI) => {
  const response = await getJamTrack(options);
  return response.json();
});

export const createMyMixdown = createAsyncThunk('jamTracks/createMixdown', async (options, thunkAPI) => {
  const response = await createMixdown(options);
  return response.json();
});

export const removeMixdown = createAsyncThunk('jamTracks/removeMixdown', async (options, thunkAPI) => {
  const { id } = options;
  await deleteMixdown(id);
  return { id };
});

export const enqueueMyMixdown = createAsyncThunk('jamTracks/enqueueMixdown', async (options, thunkAPI) => {
  const response = await enqueueMixdown(options);
  return response.json();
});


export const jamTrackSlice = createSlice({
  name: 'jamTrack',
  initialState,
  reducers: {
    addMixdown: (state, action) => {
      const payload = action.payload;
      const jamTrack = state.jamTrack;
      if (jamTrack) {
        state.jamTrack.mixdowns = [...jamTrack.mixdowns, payload];
      }
    },
    addWatchedMixdown: (state, action) => {
      const payload = action.payload;
      state.watchedMixdowns = [...state.watchedMixdowns, payload];
    },
    removeWatchedMixdown: (state, action) => {
      const payload = action.payload;
      state.watchedMixdowns = state.watchedMixdowns.filter(mix => mix.id !== payload.id);
    },
    updateMixdown: (state, action) => {
      const payload = action.payload;
      const jamTrack = state.jamTrack;
      if (jamTrack) {
        state.jamTrack.mixdowns = jamTrack.mixdowns.map(mix => {
          if (mix.id === payload.id) {
            return payload;
          }
          return mix;
        });
      }
    }
  },
  extraReducers: builder => {
    builder
      .addCase(fetchJamTrack.pending, (state, action) => {
        state.jamTrackLoadingStatus = 'loading';
        state.mixdownsLoadingStatus = 'loading';
      })
      .addCase(fetchJamTrack.fulfilled, (state, action) => {
        state.jamTrack = action.payload;
        state.jamTrackLoadingStatus = 'succeeded';
        if (action.payload.mixdowns) {
          state.mixdowns = action.payload.mixdowns;
          assignPackages(state);
          state.mixdownsLoadingStatus = 'succeeded';
        }
      })
      .addCase(fetchJamTrack.rejected, (state, action) => {
        state.jamTrackLoadingStatus = 'failed';
        state.jamTrack = null;
        state.mixdownsLoadingStatus = 'failed';
        state.mixdowns = [];
        state.error = action.error.message;
      })
      .addCase(createMyMixdown.pending, (state, action) => {
        state.newMixdownLoadingStatus = 'loading';
      })
      .addCase(createMyMixdown.fulfilled, (state, action) => {
        console.log('_DEBUG_ createMyMixdown.fulfilled', action.payload);
        state.mixdowns = [...state.mixdowns, action.payload];
        state.awaitingMixdown = action.payload;
        state.newMixdownLoadingStatus = 'succeeded';
        state.mixdownsLoadingStatus = 'succeeded';
      })
      .addCase(createMyMixdown.rejected, (state, action) => {
        state.error = action.error.message;
        state.newMixdownLoadingStatus = 'failed';
      })
      .addCase(removeMixdown.pending, (state, action) => {
        state.mixdownsLoadingStatus = 'loading';
        state.deleteMixdownStatus = 'loading';
      })
      .addCase(removeMixdown.fulfilled, (state, action) => {
        const mixdowns = state.mixdowns.filter(mix => mix.id !== action.payload.id);
        state.mixdowns = mixdowns;
        state.mixdownsLoadingStatus = 'succeeded';
        state.deleteMixdownStatus = 'succeeded';
      })
      .addCase(removeMixdown.rejected, (state, action) => {
        state.error = action.error.message;
        state.mixdownsLoadingStatus = 'failed';
        state.deleteMixdownStatus = 'failed';
      })
      .addCase(enqueueMyMixdown.fulfilled, (state, action) => {
        console.log('enqueueMyMixdown.fulfilled', action.payload);
        const enqueue = { 
          id: action.payload.jam_track_mixdown_id,
          packages: [{ ...action.payload }],
          origin: action.meta.arg.origin
        };
        state.enqueuedMixdown = enqueue;
        state.enqueuedMixdowns = [...state.enqueuedMixdowns, enqueue];
        state.mixdowns = state.mixdowns.map(mix => {
          if (mix.id === action.payload.jam_track_mixdown_id) {
            return { ...mix, ...enqueue };
          }
          return mix;
        });
        assignPackages(state);
      })
     
  }
});

//help functions
const pickMp3Package = (mixdown) => {
  return mixdown.packages.find(p => p.file_type === 'mp3' && p.encrypt_type === null && p.sample_rate === SAMPLE_RATE);
};

const pickOggPackage = (mixdown) => {
  return mixdown.packages.find(p => p.file_type === 'ogg' && p.encrypt_type === null && p.sample_rate === SAMPLE_RATE);
};

const assignPackages = (state) => {
  state.jamTrack.mp3Package = state.mixdowns.map(pickMp3Package).filter(p => p)[0] || null;
  state.jamTrack.oggPackage = state.mixdowns.map(pickOggPackage).filter(p => p)[0] || null;
};

export const { addMixdown, addWatchedMixdown, removeWatchedMixdown } = jamTrackSlice.actions;
export default jamTrackSlice.reducer;
