// Third-party Imports
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
import type { EventInput } from '@fullcalendar/core'

// Type Imports
import type { CalendarFiltersType, CalendarType } from '@/types/apps/calendarTypes'

// API Imports
import { eventService } from '@/libs/api'

// Async Thunks
export const fetchEvents = createAsyncThunk(
  'calendar/fetchEvents',
  async (params?: { start?: string; end?: string; calendar?: CalendarFiltersType }) => {
    return await eventService.listEvents(params)
  }
)

export const createEventAsync = createAsyncThunk('calendar/createEvent', async (data: any) => {
  return await eventService.createEvent(data)
})

export const updateEventAsync = createAsyncThunk(
  'calendar/updateEvent',
  async ({ id, data }: { id: string; data: any }) => {
    return await eventService.updateEvent({ id, ...data })
  }
)

export const deleteEventAsync = createAsyncThunk('calendar/deleteEvent', async (id: string) => {
  return await eventService.deleteEvent(id)
})

// Initial state - events will be loaded from API
const initialState: CalendarType & {
  loading: boolean
  error: string | null
} = {
  events: [],
  filteredEvents: [],
  selectedEvent: null,
  selectedCalendars: ['Personal', 'Business', 'Family', 'Holiday', 'ETC'],
  loading: false,
  error: null
}

const filterEventsUsingCheckbox = (events: EventInput[], selectedCalendars: CalendarFiltersType[]) => {
  return events.filter(event => selectedCalendars.includes(event.extendedProps?.calendar as CalendarFiltersType))
}

export const calendarSlice = createSlice({
  name: 'calendar',
  initialState: initialState,
  reducers: {
    filterEvents: state => {
      state.filteredEvents = state.events
    },

    addEvent: (state, action) => {
      const newEvent = { ...action.payload, id: `${parseInt(state.events[state.events.length - 1]?.id ?? '') + 1}` }

      state.events.push(newEvent)
    },

    updateEvent: (state, action: PayloadAction<EventInput>) => {
      state.events = state.events.map(event => {
        if (action.payload._def && event.id === action.payload._def.publicId) {
          return {
            id: event.id,
            url: action.payload._def.url,
            title: action.payload._def.title,
            allDay: action.payload._def.allDay,
            end: action.payload._instance.range.end,
            start: action.payload._instance.range.start,
            extendedProps: action.payload._def.extendedProps
          }
        } else if (event.id === action.payload.id) {
          return action.payload
        } else {
          return event
        }
      })
    },

    deleteEvent: (state, action) => {
      state.events = state.events.filter(event => event.id !== action.payload)
    },

    selectedEvent: (state, action) => {
      state.selectedEvent = action.payload
    },

    filterCalendarLabel: (state, action) => {
      const index = state.selectedCalendars.indexOf(action.payload)

      if (index !== -1) {
        state.selectedCalendars.splice(index, 1)
      } else {
        state.selectedCalendars.push(action.payload)
      }

      state.events = filterEventsUsingCheckbox(state.filteredEvents, state.selectedCalendars)
    },

    filterAllCalendarLabels: (state, action) => {
      state.selectedCalendars = action.payload ? ['Personal', 'Business', 'Family', 'Holiday', 'ETC'] : []
      state.events = filterEventsUsingCheckbox(state.filteredEvents, state.selectedCalendars)
    }
  },
  extraReducers: builder => {
    builder
      // Fetch Events
      .addCase(fetchEvents.pending, state => {
        state.loading = true
        state.error = null
      })
      .addCase(fetchEvents.fulfilled, (state, action) => {
        state.loading = false
        // Convert API events to FullCalendar EventInput format
        const events: EventInput[] = action.payload.map(event => ({
          id: event.id,
          title: event.title,
          start: event.start,
          end: event.end,
          allDay: event.allDay,
          extendedProps: {
            ...event.extendedProps,
            calendar: event.calendar,
            description: event.description,
            deadline: event.deadline,
            tags: event.tags,
            author: event.author
          }
        }))
        state.events = events
        state.filteredEvents = filterEventsUsingCheckbox(events, state.selectedCalendars)
      })
      .addCase(fetchEvents.rejected, (state, action) => {
        state.loading = false
        state.error = action.error.message || 'Failed to fetch events'
      })
      // Create Event
      .addCase(createEventAsync.fulfilled, (state, action) => {
        const event: EventInput = {
          id: action.payload.id,
          title: action.payload.title,
          start: action.payload.start,
          end: action.payload.end,
          allDay: action.payload.allDay,
          extendedProps: {
            ...action.payload.extendedProps,
            calendar: action.payload.calendar,
            description: action.payload.description,
            deadline: action.payload.deadline,
            tags: action.payload.tags,
            author: action.payload.author
          }
        }
        state.events.push(event)
        state.filteredEvents = filterEventsUsingCheckbox(state.events, state.selectedCalendars)
      })
      // Update Event
      .addCase(updateEventAsync.fulfilled, (state, action) => {
        const index = state.events.findIndex(event => event.id === action.payload.id)
        if (index !== -1) {
          const event: EventInput = {
            id: action.payload.id,
            title: action.payload.title,
            start: action.payload.start,
            end: action.payload.end,
            allDay: action.payload.allDay,
            extendedProps: {
              ...action.payload.extendedProps,
              calendar: action.payload.calendar,
              description: action.payload.description,
              deadline: action.payload.deadline,
              tags: action.payload.tags,
              author: action.payload.author
            }
          }
          state.events[index] = event
          state.filteredEvents = filterEventsUsingCheckbox(state.events, state.selectedCalendars)
        }
      })
      // Delete Event
      .addCase(deleteEventAsync.fulfilled, (state, action) => {
        state.events = state.events.filter(event => event.id !== action.meta.arg)
        state.filteredEvents = filterEventsUsingCheckbox(state.events, state.selectedCalendars)
      })
  }
})

export const {
  filterEvents,
  addEvent,
  updateEvent,
  deleteEvent,
  selectedEvent,
  filterCalendarLabel,
  filterAllCalendarLabels
} = calendarSlice.actions

export default calendarSlice.reducer
