import { createAsyncThunk, createSlice, type PayloadAction } from '@reduxjs/toolkit';

import api from '@/lib/axios';
import { handleToastError } from '@/lib/utils';
import { toast } from 'sonner';
import messages from '../../../messages/en.json';

// Define a type for the role
export interface Role {
    id: number;
    name: string;
    parentRole: string | null;
    departmentId: number | null;
    departmentName: string;
    teamMembersCount: number;
    businessVerticalId: number | null;
    businessVerticalName: string;
    permissionsCount: number;
    is_web_login: boolean;
}

// Define API response structure
interface ApiResponse<T = any> {
    success: boolean;
    code: number;
    message: string;
    data: T;
}

// Define the state type
interface RolesState {
    items: ApiResponse | null;
    status: 'idle' | 'loading' | 'succeeded' | 'failed';
    error: string | null;
    orgData: any;
    rolePermissions: any;
    permissions: Record<number, string>;
    dropdownItems: Role[] | null;
    selectedRole: Role | null;
    token: string | null;
    filters: {
        search: string;
        departments: string[];
        businessVerticals: string[];
        sortBy?: string;
        sortOrder?: 'ASC' | 'DESC';
        departmentId?: number;
        businessVerticalId?: number;
    };
}

// Initial state
const initialState: RolesState = {
    items: null,
    status: 'idle',
    error: null,
    orgData: null,
    rolePermissions: [],
    permissions: {},
    dropdownItems: null,
    selectedRole: null,
    token: null,
    filters: {
        search: '',
        departments: [],
        businessVerticals: [],
        sortBy: undefined,
        sortOrder: '',
        departmentId: undefined,
        businessVerticalId: undefined,
    },
};

// Async thunks
export const fetchRoles = createAsyncThunk(
    'roles/fetchRoles',
    async (
        payload: { departmentIds?: string; businessVerticalIds?: string; skip?: number; limit?: number } | undefined,
        { getState, rejectWithValue },
    ) => {
        try {
            const state = getState() as { roles: RolesState };

            const { search, departmentId, businessVerticalId, sortBy, sortOrder } = state.roles.filters;
            const limit = payload?.limit || 10;
            const skip = payload?.skip || 0;

            const params: any = {
                limit,
                skip,
                ...(sortBy && { sortBy }),
                ...(sortOrder && { sortOrder }),
                ...(payload?.businessVerticalIds && {
                    business_vertical_id: payload.businessVerticalIds,
                }),
                ...(businessVerticalId &&
                    !payload?.businessVerticalIds && {
                        business_vertical_id: businessVerticalId,
                    }),
                ...(payload?.departmentIds && {
                    department_id: payload.departmentIds,
                }),
                ...(departmentId && !payload?.departmentIds && { department_id: departmentId }),
                ...(search && typeof search === 'object' && search.name ? { search: search.name } : {}),
                ...(search && typeof search === 'string' ? { search } : {}),
            };

            const queryParams = new URLSearchParams();
            Object.entries(params).forEach(([key, value]) => {
                if (value !== undefined) {
                    queryParams.append(key, value.toString());
                }
            });

            const response = await api.get(`/roles/list?${queryParams.toString()}`);

            return response.data;
        } catch (error: any) {
            handleToastError(error);
            return rejectWithValue(error?.response?.data?.message || error.message || 'Failed to fetch roles');
        }
    },
);

export const fetchRolesDropdown = createAsyncThunk(
    'roles/fetchRolesDropdown',
    async (excludeId?: number, { rejectWithValue }) => {
        try {
            const response = await api.get(`/roles/dropdown`, {
                params: {
                    exclude_id: excludeId,
                },
            });
            return response.data;
        } catch (error: any) {
            handleToastError(error);
            return rejectWithValue(error?.response?.data?.message || error.message || 'Failed to fetch roles dropdown');
        }
    },
);

export const fetchRolesWithoutFilters = createAsyncThunk('roles/fetchRoles', async (_, { rejectWithValue }) => {
    try {
        // Use large limit to get all countries
        const queryParams = new URLSearchParams({
            limit: '100', // Large number to get all countries
            skip: '0',
        });

        const response = await api.get(`/roles/list?${queryParams.toString()}`);

        return response.data;
    } catch (error: any) {
        handleToastError(error);
        return rejectWithValue(error?.response?.data?.message || error.message || 'Failed to fetch roles');
    }
});

export const createRoles = createAsyncThunk('roles/createRole', async (roleData: Partial<Role>, { rejectWithValue }) => {
    try {
        const response = await api.post(`/roles/create`, roleData);
        return response.data;
    } catch (error: any) {
        handleToastError(error);
        return rejectWithValue(error?.response?.data?.message || error.message || 'Failed to create role');
    }
});

export const getRolesById = createAsyncThunk('roles/getRoleById', async (id: number, { rejectWithValue }) => {
    try {
        const response = await api.get(`/roles/list/${id}`);

        return response.data;
    } catch (error: any) {
        handleToastError(error);
        return rejectWithValue(error?.response?.data?.message || error.message || 'Failed to fetch role details');
    }
});

export const updateRoles = createAsyncThunk('roles/updateRole', async (roleData: Partial<Role>, { rejectWithValue }) => {
    try {
        const response = await api.put(`/roles/update/${roleData.id}`, roleData);

        if (response?.data?.success === false) {
            toast.error(response.data.message || messages.toasts.error.failed_to_update_role);
            return rejectWithValue(response.data.message || 'Update failed');
        }

        return response.data;
    } catch (error: any) {
        handleToastError(error);

        return rejectWithValue(error?.response?.data?.message || error.message || 'Failed to update role');
    }
});

export const deleteRoles = createAsyncThunk('roles/deleteRole', async (id: number, { rejectWithValue }) => {
    try {
        const response = await api.delete(`/roles/delete/${id}`);

        if (response?.data?.success === false) {
            toast.error(response.data.message || messages.toasts.error.failed_to_delete_role);
            return rejectWithValue(response.data.message || 'Deletion failed');
        }

        toast.success(messages.toasts.success.role_deleted);
        return id;
    } catch (error) {
        return rejectWithValue(error instanceof Error ? error.message : 'Failed to delete state');
    }
});

export const fetchModulesByBusinessVerticalId = createAsyncThunk(
    'roles/fetchModulesByBusinessVerticalId',
    async (businessVerticalIds: number[], { rejectWithValue }) => {
        try {
            const response = await api.post(`/module/by-business-vertical`, { ids: businessVerticalIds });
            return response.data;
        } catch (error: any) {
            handleToastError(error);
            return rejectWithValue(error?.response?.data?.message || error.message || 'Failed to fetch modules');
        }
    },
);

export const fetchPermissionsDropdown = createAsyncThunk('roles/fetchPermissionsDropdown', async (_, { rejectWithValue }) => {
    try {
        const response = await api.get(`/module`);
        return response.data;
    } catch (error: any) {
        handleToastError(error);
        return rejectWithValue(error?.response?.data?.message || error.message || 'Failed to fetch permissions');
    }
});

export const createBulkRolePermissions = createAsyncThunk(
    'rolePermissions/createBulkRolePermissions',
    async (payload: any, { rejectWithValue }) => {
        try {
            const response = await api.post(`/role-permissions/create/bulk`, payload);
            return response.data;
        } catch (error: any) {
            handleToastError(error);
            return rejectWithValue(error?.response?.data?.message || error.message || 'Failed to save permissions');
        }
    },
);

export const fetchModulePermissions = createAsyncThunk(
    'permissions/fetchModulePermissions',
    async ({ roleId, moduleId }: { roleId: number; moduleId: number }, { rejectWithValue }) => {
        try {
            const response = await api.get(`/role-permissions/list/${roleId}/${moduleId}`);

            // Check if the response and its data are valid
            const permissionData = response?.data?.data || null;

            if (!permissionData) {
                throw new Error('Permission data not found in the response');
            }

            return {
                roleId: permissionData.role_id,
                moduleId: permissionData.module_id,
                permissionType: permissionData.permission?.permission_type || null,
            };
        } catch (error: any) {
            // Improved error handling
            const errorMessage = error?.response?.data?.message || error.message || 'Failed to fetch module permissions';
            handleToastError(error);
            return rejectWithValue(errorMessage);
        }
    },
);

export const fetchRoleDetails = createAsyncThunk('roles/fetchDetails', async (id: number) => {
    try {
        const response = await api.get(`/roles/${id}`);
        return response.data;
    } catch (error: any) {
        throw error.response?.data || error.message;
    }
});

export const fetchOrgranogramDetails = createAsyncThunk('roles/fetchOrgDetails', async () => {
    try {
        const response = await api.get(`/organogram`);
        return response.data;
    } catch (error: any) {
        throw error.response?.data || error.message;
    }
});

export const fetchPermissions = createAsyncThunk('roles/fetchPermissions', async () => {
    try {
        const response = await api.get(`/permissions/list`);
        return response.data;
    } catch (error: any) {
        throw error.response?.data || error.message;
    }
});

// Slice
const rolesSlice = createSlice({
    name: 'roles',
    initialState,
    reducers: {
        setSelectedRole: (state, action: PayloadAction<Role | null>) => {
            state.selectedRole = action.payload;
        },
        setRolePermissions(state, action: PayloadAction<any>) {
            state.rolePermissions = action.payload;
        },
        updateFilters: (state, action: PayloadAction<Partial<RolesState['filters']>>) => {
            state.filters = { ...state.filters, ...action.payload };
        },
        resetFilters: (state) => {
            state.filters = initialState.filters;
        },
    },
    extraReducers: (builder) => {
        builder
            .addCase(fetchRoles.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(fetchRoles.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.items = action.payload;
                state.error = null;
            })
            .addCase(fetchRoles.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(createRoles.pending, (state) => {
                state.status = 'loading';
                state.error = null;
            })
            .addCase(createRoles.fulfilled, (state) => {
                state.status = 'succeeded';
            })
            .addCase(createRoles.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(updateRoles.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(updateRoles.fulfilled, (state) => {
                state.status = 'succeeded';
            })
            .addCase(updateRoles.rejected, (state, action) => {
                state.status = 'failed';
            })
            .addCase(getRolesById.pending, (state) => {
                state.status = 'loading';
            })
            .addCase(getRolesById.fulfilled, (state, action) => {
                state.status = 'succeeded';
                const role = action.payload;
                if (role) {
                    state.selectedRole = {
                        id: role.id,
                        name: role.name || 'N/A',
                        departmentId: role.department_id,
                        departmentName: role.department?.name || 'N/A',
                        teamMembersCount: 0,
                        businessVerticalId: role.business_vertical_id,
                        businessVerticalName: role.business_vertical?.name || 'N/A',
                        permissionsCount: role.permissions?.length || 0,
                    };
                }
            })
            .addCase(getRolesById.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(fetchModulesByBusinessVerticalId.fulfilled, (state, action) => {
                const { roleId, count } = action.payload;

                // Update only the role with matching ID
                if (state.items?.data) {
                    state.items.data = state.items.data.map((role: Role) =>
                        role.id === roleId ? { ...role, permissionsCount: count } : role,
                    );
                }
            })
            .addCase(createBulkRolePermissions.fulfilled, (state, action) => {
                state.rolePermissions = action.payload;
                state.error = null;
            })
            .addCase(createBulkRolePermissions.rejected, (state, action) => {
                state.error = action.payload as string;
            })
            .addCase(fetchModulePermissions.pending, (state) => {
                state.loading = true;
                state.error = null;
            })
            .addCase(fetchModulePermissions.fulfilled, (state, action) => {
                state.loading = false;
                state.permissions[action.payload.moduleId] = action.payload.permission;
            })
            .addCase(fetchModulePermissions.rejected, (state, action) => {
                state.loading = false;
                state.error = action.payload as string;
            })
            .addCase(fetchRolesDropdown.pending, (state) => {
                state.status = 'loading';
                state.error = null;
            })
            .addCase(fetchRolesDropdown.fulfilled, (state, action) => {
                state.status = 'succeeded';
                state.dropdownItems = action.payload;
            })
            .addCase(fetchRolesDropdown.rejected, (state, action) => {
                state.status = 'failed';
                state.error = action.payload as string;
            })
            .addCase(fetchOrgranogramDetails.pending, (state) => {
                state.loading = true;
                state.error = null;
            })
            .addCase(fetchOrgranogramDetails.fulfilled, (state, action) => {
                state.loading = false;
                state.orgData = action.payload;
            })
            .addCase(fetchOrgranogramDetails.rejected, (state, action) => {
                state.loading = false;
                state.error = action.error.message || 'Something went wrong';
            })
            .addCase(fetchPermissions.pending, (state) => {
                state.loading = true;
                state.error = null;
            })
            .addCase(fetchPermissions.fulfilled, (state, action) => {
                state.loading = false;
                state.rolePermissions = action.payload;
            })
            .addCase(fetchPermissions.rejected, (state, action) => {
                state.loading = false;
                state.error = action.error.message || 'Something went wrong';
            });
    },
});

export const { setSelectedRole, updateFilters, resetFilters, setRolePermissions } = rolesSlice.actions;

export const selectTransformedRoles = (state: { roles: RolesState }): Role[] => {
    return state.roles.items ? transformRolesData(state.roles.items) : [];
};

export default rolesSlice.reducer;
