/**
 * Copyright 2024 Phenix Real Time Solutions, Inc. Confidential and Proprietary. All Rights Reserved.
 */
import {createAsyncThunk, createSelector, createSlice, PayloadAction} from '@reduxjs/toolkit';
import {Channel} from '@phenixrts/sdk';
import channelService from '../../services/channel.service';
import {RootState} from '../index';

// Publishing state interface
export interface ChannelPublishingState {
  channelId: string;
  isOnline: boolean;
  publisherCount: number;
  streamCount: number;
  lastUpdated: string;
}

export interface ChannelsPublishingState {
  publishingState: ChannelPublishingState[];
  isLoading: boolean;
  error: string | null;
  lastFetched: string | null;
}

const initialState: ChannelsPublishingState = {
  publishingState: [],
  isLoading: false,
  error: null,
  lastFetched: null
};

// Selectors
export const channelsPublishingSelector = (state: RootState): ChannelsPublishingState => 
  state.channelsPublishing;

export const selectChannelsPublishingState = createSelector(
  [channelsPublishingSelector],
  (channelsPublishing: ChannelsPublishingState) => channelsPublishing.publishingState
);

export const selectChannelsPublishingLoading = createSelector(
  [channelsPublishingSelector],
  (channelsPublishing: ChannelsPublishingState) => channelsPublishing.isLoading
);

export const selectChannelPublishingState = createSelector(
  [selectChannelsPublishingState, (_: RootState, channelId: string) => channelId],
  (publishingStates: ChannelPublishingState[], channelId: string) =>
    publishingStates.find(state => state.channelId === channelId)
);

// Async thunks
export const fetchChannelsPublishingState = createAsyncThunk(
  'channelsPublishing/fetchChannelsPublishingState',
  async (channels: Channel[], {rejectWithValue}) => {
    try {
      const publishingStates = await Promise.all(
        channels.map(async (channel): Promise<ChannelPublishingState> => {
          try {
            const publisherCount = await channelService.getPublisherCount(channel.channelId);
            return {
              channelId: channel.channelId,
              isOnline: publisherCount > 0,
              publisherCount,
              streamCount: publisherCount, // Assuming 1:1 for now
              lastUpdated: new Date().toISOString()
            };
          } catch (error) {
            // If we can't get publisher count, assume offline
            return {
              channelId: channel.channelId,
              isOnline: false,
              publisherCount: 0,
              streamCount: 0,
              lastUpdated: new Date().toISOString()
            };
          }
        })
      );

      return publishingStates;
    } catch (error) {
      return rejectWithValue(error instanceof Error ? error.message : 'Failed to fetch publishing state');
    }
  }
);

export const updateChannelPublishingState = createAsyncThunk(
  'channelsPublishing/updateChannelPublishingState',
  async (channelId: string, {rejectWithValue}) => {
    try {
      const publisherCount = await channelService.getPublisherCount(channelId);
      return {
        channelId,
        isOnline: publisherCount > 0,
        publisherCount,
        streamCount: publisherCount,
        lastUpdated: new Date().toISOString()
      } as ChannelPublishingState;
    } catch (error) {
      return rejectWithValue(error instanceof Error ? error.message : 'Failed to update publishing state');
    }
  }
);

// Slice
const channelsPublishingSlice = createSlice({
  name: 'channelsPublishing',
  initialState,
  reducers: {
    clearPublishingState: (state) => {
      state.publishingState = [];
      state.error = null;
    },
    setPublishingError: (state, action: PayloadAction<string | null>) => {
      state.error = action.payload;
    },
    updateChannelState: (state, action: PayloadAction<ChannelPublishingState>) => {
      const index = state.publishingState.findIndex(
        item => item.channelId === action.payload.channelId
      );
      
      if (index >= 0) {
        state.publishingState[index] = action.payload;
      } else {
        state.publishingState.push(action.payload);
      }
    }
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchChannelsPublishingState.pending, (state) => {
        state.isLoading = true;
        state.error = null;
      })
      .addCase(fetchChannelsPublishingState.fulfilled, (state, action) => {
        state.isLoading = false;
        state.publishingState = action.payload;
        state.lastFetched = new Date().toISOString();
        state.error = null;
      })
      .addCase(fetchChannelsPublishingState.rejected, (state, action) => {
        state.isLoading = false;
        state.error = action.payload as string;
      })
      .addCase(updateChannelPublishingState.fulfilled, (state, action) => {
        const index = state.publishingState.findIndex(
          item => item.channelId === action.payload.channelId
        );
        
        if (index >= 0) {
          state.publishingState[index] = action.payload;
        } else {
          state.publishingState.push(action.payload);
        }
      })
      .addCase(updateChannelPublishingState.rejected, (state, action) => {
        state.error = action.payload as string;
      });
  }
});

export const {clearPublishingState, setPublishingError, updateChannelState} = channelsPublishingSlice.actions;
export default channelsPublishingSlice.reducer;