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

// Type Imports
import type { ColumnType, TaskType } from '@/types/apps/kanbanTypes'

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

// Async Thunks
export const fetchBoard = createAsyncThunk('kanban/fetchBoard', async () => {
  return await kanbanService.getBoard()
})

export const createColumnAsync = createAsyncThunk('kanban/createColumn', async (title: string) => {
  return await kanbanService.createColumn(title)
})

export const updateColumnAsync = createAsyncThunk(
  'kanban/updateColumn',
  async ({ columnId, data }: { columnId: number; data: any }) => {
    return await kanbanService.updateColumn(columnId, data)
  }
)

export const deleteColumnAsync = createAsyncThunk('kanban/deleteColumn', async (columnId: number) => {
  return await kanbanService.deleteColumn(columnId)
})

export const createTaskAsync = createAsyncThunk('kanban/createTask', async (data: any) => {
  return await kanbanService.createTask(data)
})

export const updateTaskAsync = createAsyncThunk(
  'kanban/updateTask',
  async ({ taskId, data }: { taskId: number; data: any }) => {
    return await kanbanService.updateTask(taskId, data)
  }
)

export const deleteTaskAsync = createAsyncThunk('kanban/deleteTask', async (taskId: number) => {
  return await kanbanService.deleteTask(taskId)
})

export const moveTaskAsync = createAsyncThunk(
  'kanban/moveTask',
  async ({
    taskId,
    fromColumnId,
    toColumnId,
    position
  }: {
    taskId: number
    fromColumnId: number
    toColumnId: number
    position: number
  }) => {
    return await kanbanService.moveTask(taskId, fromColumnId, toColumnId, position)
  }
)

const initialState: {
  columns: ColumnType[]
  tasks: TaskType[]
  currentTaskId?: number
  loading: boolean
  error: string | null
} = {
  columns: [],
  tasks: [],
  currentTaskId: undefined,
  loading: false,
  error: null
}

export const kanbanSlice = createSlice({
  name: 'kanban',
  initialState,
  reducers: {
    addColumn: (state, action) => {
      const maxId = Math.max(...state.columns.map(column => column.id))

      const newColumn: ColumnType = {
        id: maxId + 1,
        title: action.payload,
        taskIds: []
      }

      state.columns.push(newColumn)
    },

    editColumn: (state, action) => {
      const { id, title } = action.payload

      const column = state.columns.find(column => column.id === id)

      if (column) {
        column.title = title
      }
    },

    deleteColumn: (state, action: PayloadAction<{ columnId: number }>) => {
      const { columnId } = action.payload
      const column = state.columns.find(column => column.id === columnId)

      state.columns = state.columns.filter(column => column.id !== columnId)

      if (column) {
        state.tasks = state.tasks.filter(task => !column.taskIds.includes(task.id))
      }
    },

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

    updateColumnTaskIds: (state, action) => {
      const { id, tasksList } = action.payload

      state.columns = state.columns.map(column => {
        if (column.id === id) {
          return { ...column, taskIds: tasksList.map((task: TaskType) => task.id) }
        }

        return column
      })
    },

    addTask: (state, action: PayloadAction<TaskType>) => {
      const task = action.payload
      state.tasks.push(task)
      const column = state.columns.find(column => column.id === action.payload.id)

      if (column) {
        column.taskIds.push(task.id)
      }
    },

    editTask: (state, action) => {
      const { id, title, badgeText, dueDate } = action.payload

      const task = state.tasks.find(task => task.id === id)

      if (task) {
        task.title = title
        task.badgeText = badgeText
        task.dueDate = dueDate
      }
    },

    deleteTask: (state, action) => {
      const taskId = action.payload

      state.tasks = state.tasks.filter(task => task.id !== taskId)
      state.columns = state.columns.map(column => {
        return {
          ...column,
          taskIds: column.taskIds.filter(id => id !== taskId)
        }
      })
    },

    getCurrentTask: (state, action: PayloadAction<number | undefined>) => {
      state.currentTaskId = action.payload
    }
  },
  extraReducers: builder => {
    builder
      // Fetch Board
      .addCase(fetchBoard.pending, state => {
        state.loading = true
        state.error = null
      })
      .addCase(fetchBoard.fulfilled, (state, action) => {
        state.loading = false
        state.columns = action.payload.columns
        state.tasks = action.payload.tasks
      })
      .addCase(fetchBoard.rejected, (state, action) => {
        state.loading = false
        state.error = action.error.message || 'Failed to fetch board'
      })
      // Create Column
      .addCase(createColumnAsync.fulfilled, (state, action) => {
        state.columns.push(action.payload)
      })
      // Update Column
      .addCase(updateColumnAsync.fulfilled, (state, action) => {
        const index = state.columns.findIndex(col => col.id === action.payload.id)
        if (index !== -1) {
          state.columns[index] = action.payload
        }
      })
      // Delete Column
      .addCase(deleteColumnAsync.fulfilled, (state, action) => {
        state.columns = state.columns.filter(col => col.id !== action.meta.arg)
        // Remove tasks from deleted column
        const deletedColumn = state.columns.find(col => col.id === action.meta.arg)
        if (deletedColumn) {
          state.tasks = state.tasks.filter(task => !deletedColumn.taskIds.includes(task.id))
        }
      })
      // Create Task
      .addCase(createTaskAsync.fulfilled, (state, action) => {
        state.tasks.push(action.payload)
        const column = state.columns.find(col => col.id === action.payload.id)
        if (column) {
          column.taskIds.push(action.payload.id)
        }
      })
      // Update Task
      .addCase(updateTaskAsync.fulfilled, (state, action) => {
        const index = state.tasks.findIndex(task => task.id === action.payload.id)
        if (index !== -1) {
          state.tasks[index] = action.payload
        }
        // Update column if task moved
        if (action.meta.arg.data.columnId !== undefined) {
          state.columns.forEach(col => {
            col.taskIds = col.taskIds.filter(id => id !== action.payload.id)
          })
          const targetColumn = state.columns.find(col => col.id === action.meta.arg.data.columnId)
          if (targetColumn) {
            targetColumn.taskIds.push(action.payload.id)
          }
        }
      })
      // Delete Task
      .addCase(deleteTaskAsync.fulfilled, (state, action) => {
        state.tasks = state.tasks.filter(task => task.id !== action.meta.arg)
        state.columns.forEach(col => {
          col.taskIds = col.taskIds.filter(id => id !== action.meta.arg)
        })
      })
      // Move Task
      .addCase(moveTaskAsync.fulfilled, (state, action) => {
        state.columns = action.payload
      })
  }
})

export const {
  addColumn,
  editColumn,
  deleteColumn,
  updateColumns,
  updateColumnTaskIds,
  addTask,
  editTask,
  deleteTask,
  getCurrentTask
} = kanbanSlice.actions

export default kanbanSlice.reducer
