/* eslint no-param-reassign: "error" */
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import type { AxiosResponse } from 'axios';
import axios from 'axios';

import environment from '../../Environments/environment';
import type { CompanyTypeInterface } from '../../Pages/ChooseCompanyType/companyTypeHelper';
import type { CompanyDbModel } from '../../Pages/Companies/Components/CompaniesComponents.helper';
import type { PlanModel } from '../../Store/User/user-context.helper';

const { apiUrl, backendRoutes } = environment;

interface CompaniesState {
	selectedCompany: CompanyDbModel | null;
	companiesList: CompanyDbModel[] | null; // should contain only companies with active invites
	allCompaniesList: CompanyDbModel[] | null; // should contain all companies, even with revoked invites
}

const initialState: CompaniesState = {
	selectedCompany: null,
	companiesList: null,
	allCompaniesList: null
};

const companiesSlice = createSlice({
	name: 'companies',
	initialState,
	reducers: {
		selectCompany: (state, action) => {
			state.selectedCompany = action.payload;
			localStorage.setItem('selectedCompany', JSON.stringify(action.payload));
		}
	},
	extraReducers: (builder) => {
		builder
			.addCase(fetchCompanyData.pending, (state, action) => {
				state.selectedCompany = null;
				state.companiesList = null;
				state.allCompaniesList = null;
			})
			.addCase(fetchCompanyData.fulfilled, (state, action) => {
				if (action.payload) {
					state.allCompaniesList = action.payload;
					state.companiesList = action.payload.filter(
						(company) => company.invite_status === 'accepted' || company.myCompany
					);
					if (localStorage.getItem('selectedCompany')) {
						const selectedCompany = JSON.parse(localStorage.getItem('selectedCompany') as string);
						const selectedCompanyFoundInCompanies = state.companiesList?.find(
							(company) => company.company_id === selectedCompany.company_id
						);
						if (selectedCompanyFoundInCompanies) {
							state.selectedCompany = selectedCompanyFoundInCompanies;
						}
					}
				}
			})
			.addCase(createCompany.fulfilled, (state, action) => {
				if (action.payload) {
					if (state.allCompaniesList) {
						state.allCompaniesList?.push(action.payload);
					} else {
						state.allCompaniesList = [action.payload];
					}

					if (state.companiesList) {
						state.companiesList?.push(action.payload);
						state.selectedCompany = action.payload;
						localStorage.setItem('selectedCompany', JSON.stringify(action.payload));
					} else {
						state.companiesList = [action.payload];
					}
				}
			})
			.addCase(createCompany.rejected, (state, action) => {
				if (action.payload) {
					// Handle the error here, you can store it in the state or display it to the user
					throw new Error((action.payload as any).error);
				}
			})
			.addCase(updateCompany.fulfilled, (state, action) => {
				if (action.payload as [CompanyDbModel, string]) {
					const [companyData, editCompanyId] = action.payload;
					if (state.allCompaniesList) {
						state.allCompaniesList = state.allCompaniesList.map((company) =>
							company.company_id === editCompanyId ? (companyData as CompanyDbModel) : company
						);
					}
					if (state.companiesList) {
						state.companiesList = state.companiesList.map((company) =>
							company.company_id === editCompanyId ? (companyData as CompanyDbModel) : company
						);
					}
				}
			})
			.addCase(updateCompany.rejected, (state, action) => {
				if (action.payload) {
					// Handle the error here, you can store it in the state or display it to the user
					throw new Error((action.payload as any).error);
				}
			})
			.addCase(updateCompanysDashboardSelection.fulfilled, (state, action) => {
				if (action.payload as [CompanyDbModel, string]) {
					const [companyData, editCompanyId] = action.payload;
					if (state.allCompaniesList) {
						state.allCompaniesList = state.allCompaniesList.map((company) =>
							company.company_id === editCompanyId ? (companyData as CompanyDbModel) : company
						);
					}
					if (state.companiesList) {
						state.companiesList = state.companiesList.map((company) =>
							company.company_id === editCompanyId ? (companyData as CompanyDbModel) : company
						);
					}
					if (state.selectedCompany?.company_id === editCompanyId) {
						state.selectedCompany = companyData as CompanyDbModel;
					}
				}
			})
			.addCase(deleteCompany.fulfilled, (state, action) => {
				if (action.payload) {
					if (
						state.companiesList &&
						state.companiesList.find((company) => company.company_id === action.payload?.company_id)
					) {
						// remove from allCompaniesList
						if (state.allCompaniesList) {
							state.allCompaniesList = state.allCompaniesList.filter(
								(company) => company.company_id !== action.payload?.company_id
							);
						}

						// remove from companiesList
						state.companiesList = state.companiesList.filter(
							(company) => company.company_id !== action.payload?.company_id
						);

						// set the first company in the list as active
						if (state.selectedCompany?.company_id === action.payload?.company_id) {
							state.selectedCompany = state.companiesList[0];
						}
					}
				}
			})
			.addCase(setCompanyPlan.fulfilled, (state, action) => {
				if (action.payload) {
					const updatedCompany = state.companiesList?.find(
						(company) => company.company_id === action.payload.company_id
					);
					if (updatedCompany) {
						updatedCompany.plan = action.payload.plan;
					}
					if (state.selectedCompany) {
						state.selectedCompany.plan = action.payload.plan;
					}
				}
			})
			.addCase(downgradeCompanyPlan.fulfilled, (state, action) => {
				if (action.payload) {
					const updatedCompany = state.companiesList?.find(
						(company) => company.company_id === action.payload.company_id
					);
					if (updatedCompany) {
						updatedCompany.downgradePlan = action.payload.downgradePlan;
					}
					if (state.selectedCompany) {
						state.selectedCompany.downgradePlan = action.payload.downgradePlan;
					}
				}
			})
			.addCase(cancelDowngradeCompanyPlan.fulfilled, (state, action) => {
				if (action.payload) {
					const updatedCompany = state.companiesList?.find(
						(company) => company.company_id === action.payload.company_id
					);
					if (updatedCompany) {
						delete updatedCompany.downgradePlan;
					}
					if (state.selectedCompany) {
						delete state.selectedCompany.downgradePlan;
					}
				}
			})
			.addCase(payAndSetCompanyPlan.fulfilled, (state, action) => {
				if (action.payload) {
					const updatedCompany = state.companiesList?.find(
						(company) => company.company_id === action.payload.company_id
					);
					if (updatedCompany) {
						updatedCompany.plan = action.payload.plan;
					}
					if (state.selectedCompany) {
						state.selectedCompany.plan = action.payload.plan;
					}
				}
			});
	}
});

export const fetchCompanyData = createAsyncThunk('companies/fetchCompaniesList', async () => {
	// fetch associated company data
	const companies = await axios
		.get(apiUrl + backendRoutes.companies)
		.then((response: AxiosResponse<CompanyDbModel[]>) => response.data)
		.catch((error) => {
			// if no companies are associated with this user:
			if (error.response.status === 404 && error.response.data === 'No companies found') {
				return [];
			}
			console.error(error.message);
			return null;
		});
	return companies;
});

export const createCompany = createAsyncThunk(
	'companies/create',
	async (payload: CompanyTypeInterface, { rejectWithValue }) => {
		try {
			const company: CompanyDbModel = await axios
				.post(apiUrl + backendRoutes.companyRegistration, {
					userAndCompanyInfo: payload
				})
				.then((response: AxiosResponse<CompanyDbModel>) => response.data);
			return company;
		} catch (error: any) {
			return rejectWithValue({ error: error.message });
		}
	}
);

export const updateCompany = createAsyncThunk(
	'companies/update',
	async (payload: CompanyTypeInterface, { rejectWithValue }) => {
		if (!payload.companyId || payload.companyId === '') {
			return rejectWithValue({ error: 'No company_id provided' });
		}
		try {
			const company: CompanyDbModel = await axios
				.patch(apiUrl + backendRoutes.updateCompany, {
					userAndCompanyInfo: payload
				})
				.then(
					(response: AxiosResponse<CompanyDbModel>) =>
						// return JSON.parse(response.data);
						response.data
				);
			return [company, payload.companyId];
		} catch (error: any) {
			return rejectWithValue({ error: error.message });
		}
	}
);

export const updateCompanysDashboardSelection = createAsyncThunk(
	'companies/updateDashboardSelection',
	async (
		payload: { companyId: string; dashboardSelection: CompanyDbModel['dashboardSelection'] },
		{ rejectWithValue }
	) => {
		if (!payload) {
			return rejectWithValue({ error: 'No payload provided' });
		}
		try {
			const company: CompanyDbModel = await axios
				.patch(apiUrl + backendRoutes.updateCompanysDashboard, {
					dashboardSelection: payload
				})
				.then(
					(response: AxiosResponse<CompanyDbModel>) =>
						// return JSON.parse(response.data);
						response.data
				);
			return [company, payload.companyId];
		} catch (error: any) {
			return rejectWithValue({ error: error.message });
		}
	}
);

export const deleteCompany = createAsyncThunk(
	'companies/delete',
	async (payload: { company_id: string }) => {
		try {
			const removedCompanyId = await axios
				.post(apiUrl + backendRoutes.removeCompany, {
					company_id: payload.company_id
				})
				.then((response: AxiosResponse<{ company_id: string }>) => response.data);
			return removedCompanyId;
		} catch (error: any) {
			// if the compnay did not exist:
			// if (error.response.status === 404 && error.response.data === 'Company not found.') {
			// 	return [];
			// }
			console.error(error.message);
			return null;
		}
	}
);

export const setCompanyPlan = createAsyncThunk(
	'companies/setCompanyPlan',
	async (payload: { company_id: string; newSelectedPlan: PlanModel }, { rejectWithValue }) => {
		try {
			const plan: any = await axios.post(apiUrl + backendRoutes.account.updatePlan, {
				planId: payload.newSelectedPlan.id,
				companyId: payload.company_id
			});
			console.log('plan when updating:', plan);
			return {
				company_id: payload.company_id,
				plan: plan.data
			};
		} catch (error: any) {
			return rejectWithValue({ error: error.message });
		}
	}
);

export const downgradeCompanyPlan = createAsyncThunk(
	'companies/downgradeCompanyPlan',
	async (payload: { company_id: string; newSelectedPlan: PlanModel }, { rejectWithValue }) => {
		try {
			const plan: any = await axios.patch(apiUrl + backendRoutes.account.downgradePlan, {
				planId: payload.newSelectedPlan.id,
				companyId: payload.company_id
			});
			return {
				company_id: payload.company_id,
				downgradePlan: plan.data
			};
		} catch (error: any) {
			return rejectWithValue({ error: error.message });
		}
	}
);

export const cancelDowngradeCompanyPlan = createAsyncThunk(
	'companies/cancelDowngradeCompanyPlan',
	async (payload: { company_id: string }, { rejectWithValue }) => {
		try {
			const plan: any = await axios.patch(apiUrl + backendRoutes.account.cancelDowngrade, {
				companyId: payload.company_id
			});
			return {
				company_id: payload.company_id
			};
		} catch (error: any) {
			return rejectWithValue({ error: error.message });
		}
	}
);

export const payAndSetCompanyPlan = createAsyncThunk(
	'companies/payAndSetCompanyPlan',
	async (
		payload: { paymentDetails: any; company_id: string; newSelectedPlan: PlanModel },
		{ rejectWithValue }
	) => {
		try {
			const plan: { data: PlanModel } = await axios.post(
				apiUrl + backendRoutes.account.addPayment,
				{
					paymentDetails: payload.paymentDetails,
					planId: payload.newSelectedPlan.id,
					companyId: payload.company_id
				}
			);
			return {
				company_id: payload.company_id,
				plan: plan.data
			};
		} catch (error: any) {
			return rejectWithValue({ error: error.message });
		}
	}
);

export const { selectCompany } = companiesSlice.actions;

export default companiesSlice.reducer;
