import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { getSessionHistory, joinSession as apiJoinSession, leaveSession as apiLeaveSession } from '../../helpers/rest';

// Async thunks for API calls
export const fetchActiveSession = createAsyncThunk(
  'activeSession/fetch',
  async (sessionId, { rejectWithValue }) => {
    try {
      const response = await getSessionHistory(sessionId);
      return await response.json();
    } catch (error) {
      return rejectWithValue(error.message);
    }
  }
);

export const joinActiveSession = createAsyncThunk(
  'activeSession/join',
  async ({ sessionId, options }, { rejectWithValue }) => {
    try {
      const response = await apiJoinSession(sessionId, options);
      return await response.json();
    } catch (error) {
      return rejectWithValue(error.message);
    }
  }
);

export const leaveActiveSession = createAsyncThunk(
  'activeSession/leave',
  async (clientId, { rejectWithValue }) => {
    try {
      await apiLeaveSession(clientId);
      return clientId;
    } catch (error) {
      return rejectWithValue(error.message);
    }
  }
);

const initialState = {
  // Session data
  sessionId: null,
  sessionData: null,
  sessionRules: null,
  subscriptionRules: null,

  // Lifecycle state
  joinStatus: 'idle', // 'idle' | 'checking' | 'joining' | 'joined' | 'leaving' | 'left'
  guardsPassed: false,
  hasJoined: false,

  // Participants
  participants: [],

  // Tracks
  userTracks: [],
  jamTracks: [],
  backingTracks: [],
  selectedJamTrack: null,
  jamTrackStems: [],

  // Backing track data (for currently active backing track)
  backingTrackData: null,

  // JamTrack data (for currently active JamTrack player)
  jamTrackData: null,

  // Mixdown management (Phase 5)
  availableMixdowns: [], // Array of mixdown objects: { id, type: 'master'|'custom-mix'|'stem', name, jamTrackId, packageId }
  activeMixdown: null, // Currently selected mixdown object
  mixdownCache: {}, // Map of packageId -> { metadata, sampleRate, fileType, encryptType }

  // Recording state
  recordingState: {
    isRecording: false,
    recordingId: null,
    recordedTracks: []
  },

  // Connection state
  connectionStatus: 'disconnected', // 'connected' | 'disconnected' | 'reconnecting'
  showConnectionAlert: false,

  // Loading and errors
  loading: false,
  error: null
};

export const activeSessionSlice = createSlice({
  name: 'activeSession',
  initialState,
  reducers: {
    // Session lifecycle
    setSessionId: (state, action) => {
      state.sessionId = action.payload;
    },

    setGuardsPassed: (state, action) => {
      state.guardsPassed = action.payload;
    },

    // Session metadata
    setSessionRules: (state, action) => {
      state.sessionRules = action.payload;
    },

    setSubscriptionRules: (state, action) => {
      state.subscriptionRules = action.payload;
    },

    // Connection management
    setConnectionStatus: (state, action) => {
      state.connectionStatus = action.payload;
      state.showConnectionAlert = action.payload === 'disconnected';
    },

    // Participants
    addParticipant: (state, action) => {
      const exists = state.participants.find(p => p.id === action.payload.id);
      if (!exists) {
        state.participants.push(action.payload);
      }
    },

    removeParticipant: (state, action) => {
      state.participants = state.participants.filter(p => p.id !== action.payload);
    },

    updateParticipant: (state, action) => {
      const index = state.participants.findIndex(p => p.id === action.payload.id);
      if (index !== -1) {
        state.participants[index] = { ...state.participants[index], ...action.payload };
      }
    },

    // Update a specific track's instrument for a participant in sessionData
    updateParticipantTrackInstrument: (state, action) => {
      const { clientId, trackId, instrumentId } = action.payload;
      if (state.sessionData?.participants) {
        const participant = state.sessionData.participants.find(p => p.client_id === clientId);
        if (participant?.tracks) {
          const track = participant.tracks.find(t => t.client_track_id === trackId);
          if (track) {
            track.instrument_id = instrumentId;
          }
        }
      }
    },

    // Tracks
    setUserTracks: (state, action) => {
      state.userTracks = action.payload;
    },

    addUserTrack: (state, action) => {
      state.userTracks.push(action.payload);
    },

    removeUserTrack: (state, action) => {
      state.userTracks = state.userTracks.filter(t => t.id !== action.payload);
    },

    updateUserTrack: (state, action) => {
      const index = state.userTracks.findIndex(t => t.id === action.payload.id);
      if (index !== -1) {
        state.userTracks[index] = { ...state.userTracks[index], ...action.payload };
      }
    },

    // Jam Tracks
    setSelectedJamTrack: (state, action) => {
      state.selectedJamTrack = action.payload;
    },

    setJamTrackStems: (state, action) => {
      state.jamTrackStems = action.payload;
    },

    addJamTrack: (state, action) => {
      const exists = state.jamTracks.find(t => t.id === action.payload.id);
      if (!exists) {
        state.jamTracks.push(action.payload);
      }
    },

    removeJamTrack: (state, action) => {
      state.jamTracks = state.jamTracks.filter(t => t.id !== action.payload);
    },

    // Backing Tracks
    addBackingTrack: (state, action) => {
      const exists = state.backingTracks.find(t => t.id === action.payload.id);
      if (!exists) {
        state.backingTracks.push(action.payload);
      }
    },

    removeBackingTrack: (state, action) => {
      state.backingTracks = state.backingTracks.filter(t => t.id !== action.payload);
    },

    setBackingTrackData: (state, action) => {
      state.backingTrackData = action.payload;
    },

    clearBackingTrackData: (state) => {
      state.backingTrackData = null;
    },

    setJamTrackData: (state, action) => {
      state.jamTrackData = action.payload;
    },

    clearJamTrackData: (state) => {
      state.jamTrackData = null;
    },

    // Recording
    startRecording: (state, action) => {
      state.recordingState.isRecording = true;
      state.recordingState.recordingId = action.payload;
    },

    stopRecording: (state) => {
      state.recordingState.isRecording = false;
    },

    addRecordedTrack: (state, action) => {
      state.recordingState.recordedTracks.push(action.payload);
    },

    clearRecordedTracks: (state) => {
      state.recordingState.recordedTracks = [];
    },

    // Phase 5: Mixdown management
    setAvailableMixdowns: (state, action) => {
      state.availableMixdowns = action.payload;
    },

    setActiveMixdown: (state, action) => {
      state.activeMixdown = action.payload;
    },

    cacheMixdownPackage: (state, action) => {
      state.mixdownCache[action.payload.packageId] = action.payload.metadata;
    },

    clearMixdowns: (state) => {
      state.availableMixdowns = [];
      state.activeMixdown = null;
      state.mixdownCache = {};
    },

    // Phase 4: Update session data (for partial updates)
    updateSessionData: (state, action) => {
      if (state.sessionData) {
        state.sessionData = { ...state.sessionData, ...action.payload };
      }
    },

    // Clear session on leave
    clearSession: (state) => {
      return { ...initialState };
    }
  },

  extraReducers: (builder) => {
    builder
      // Fetch active session
      .addCase(fetchActiveSession.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchActiveSession.fulfilled, (state, action) => {
        state.loading = false;
        state.sessionData = action.payload;
        state.sessionId = action.payload.id;
      })
      .addCase(fetchActiveSession.rejected, (state, action) => {
        state.loading = false;
        state.error = action.payload;
      })

      // Join session
      .addCase(joinActiveSession.pending, (state) => {
        state.joinStatus = 'joining';
        state.error = null;
      })
      .addCase(joinActiveSession.fulfilled, (state, action) => {
        state.joinStatus = 'joined';
        state.hasJoined = true;
        state.sessionData = action.payload;
      })
      .addCase(joinActiveSession.rejected, (state, action) => {
        state.joinStatus = 'idle';
        state.error = action.payload;
      })

      // Leave session
      .addCase(leaveActiveSession.pending, (state) => {
        state.joinStatus = 'leaving';
      })
      .addCase(leaveActiveSession.fulfilled, (state) => {
        return { ...initialState };
      })
      .addCase(leaveActiveSession.rejected, (state, action) => {
        state.error = action.payload;
      });
  }
});

export const {
  setSessionId,
  setGuardsPassed,
  setSessionRules,
  setSubscriptionRules,
  setConnectionStatus,
  addParticipant,
  removeParticipant,
  updateParticipant,
  updateParticipantTrackInstrument,
  setUserTracks,
  addUserTrack,
  removeUserTrack,
  updateUserTrack,
  setSelectedJamTrack,
  setJamTrackStems,
  addJamTrack,
  removeJamTrack,
  addBackingTrack,
  removeBackingTrack,
  setBackingTrackData,
  clearBackingTrackData,
  setJamTrackData,
  clearJamTrackData,
  startRecording,
  stopRecording,
  addRecordedTrack,
  clearRecordedTracks,
  setAvailableMixdowns,
  setActiveMixdown,
  cacheMixdownPackage,
  clearMixdowns,
  updateSessionData,
  clearSession
} = activeSessionSlice.actions;

export default activeSessionSlice.reducer;

// Selectors
export const selectActiveSession = (state) => state.activeSession.sessionData;
export const selectSessionId = (state) => state.activeSession.sessionId;
export const selectInSession = (state) => state.activeSession.sessionId !== null; // Phase 4: replaces inSession() function
export const selectSessionRules = (state) => state.activeSession.sessionRules;
export const selectSubscriptionRules = (state) => state.activeSession.subscriptionRules;
export const selectJoinStatus = (state) => state.activeSession.joinStatus;
export const selectHasJoined = (state) => state.activeSession.hasJoined;
export const selectGuardsPassed = (state) => state.activeSession.guardsPassed;
export const selectParticipants = (state) => state.activeSession.participants;
export const selectUserTracks = (state) => state.activeSession.userTracks;
export const selectJamTracks = (state) => state.activeSession.jamTracks;
export const selectBackingTracks = (state) => state.activeSession.backingTracks;
export const selectSelectedJamTrack = (state) => state.activeSession.selectedJamTrack;
export const selectJamTrackStems = (state) => state.activeSession.jamTrackStems;
export const selectBackingTrackData = (state) => state.activeSession.backingTrackData;
export const selectJamTrackData = (state) => state.activeSession.jamTrackData;
export const selectConnectionStatus = (state) => state.activeSession.connectionStatus;
export const selectShowConnectionAlert = (state) => state.activeSession.showConnectionAlert;
export const selectRecordingState = (state) => state.activeSession.recordingState;
export const selectIsRecording = (state) => state.activeSession.recordingState.isRecording;
export const selectRecordedTracks = (state) => state.activeSession.recordingState.recordedTracks;
export const selectActiveSessionLoading = (state) => state.activeSession.loading;
export const selectActiveSessionError = (state) => state.activeSession.error;
export const selectAvailableMixdowns = (state) => state.activeSession.availableMixdowns;
export const selectActiveMixdown = (state) => state.activeSession.activeMixdown;
export const selectMixdownCache = (state) => state.activeSession.mixdownCache;
