/* 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 { CompanyDbModel } from '../../Pages/Companies/Components/CompaniesComponents.helper';
import type { FinancialsModel } from '../../Pages/Financials/Components/FinancialsForm/FinancialsForm.helper';
import { selectedDemoFinancials } from '../../Pages/Financials/Components/UI/demo-user.helper';

const { apiUrl, backendRoutes } = environment;

interface FinancialsState {
	financialsList: FinancialsModel[] | null;
	selectedFinancials: FinancialsModel[] | null;
	editFinancialtemId: FinancialsModel[] | null;
}

const initialState: FinancialsState = {
	financialsList: null,
	selectedFinancials: null,
	editFinancialtemId: null // if not null we consider this item's id is selected for editing
};

const selectedFinancialsIndexes = ['first-financial', 'second-financial', 'third-financial'];
const helperClearAllFinancialsInLocalStorage = () => {
	const p = performance.now();
	// remove current values
	selectedFinancialsIndexes.forEach((financial) => {
		localStorage.removeItem(financial);
	});
	console.log(' - - it took', performance.now() - p, 'ms to perform the LS operations');
};
const helperSetFinancialsInLocalStorage = (financials: FinancialsModel[]) => {
	const p = performance.now();
	helperClearAllFinancialsInLocalStorage();

	if (financials) {
		financials.forEach((financial, index) => {
			localStorage.setItem(selectedFinancialsIndexes[index], JSON.stringify(financial));
		});
	}
	console.log('it took', performance.now() - p, 'ms to perform the LS operations');
};

const sortFinancialRecordsByYearStart = (financialsList: FinancialsModel[]): FinancialsModel[] =>
	financialsList.sort((a, b) => {
		// Create a date by concatenating Month Start and Year Start
		const dateA = new Date(`${a.input['Month Start']} 1, ${a.input['Year Start']}`).getTime();
		const dateB = new Date(`${b.input['Month Start']} 1, ${b.input['Year Start']}`).getTime();

		// Compare the two dates
		return dateA - dateB; // Sort in descending order
	});

const financialsSlice = createSlice({
	name: 'financials',
	initialState,
	reducers: {
		setSelectedFinancials: (state, action) => {
			if (action.payload) {
				const selectedFinancials: FinancialsModel[] = [];
				Object.keys(action.payload).forEach((financial, index) => {
					if (action.payload[financial] === true) {
						if (state && state.financialsList) {
							const f = state.financialsList.find(
								(financials) => financials && financials.financials_id === financial
							);
							selectedFinancials.push(f as FinancialsModel);
							// localStorage.setItem(selectedFinancialsIndexes[index], JSON.stringify(f));
						}
					}
				});
				state.selectedFinancials = sortFinancialRecordsByYearStart(selectedFinancials);
				helperSetFinancialsInLocalStorage(selectedFinancials);
				localStorage.setItem('selectedFinancials', JSON.stringify(selectedFinancials));
			}
		},
		setSelectedFinancial: (state, action) => {
			if (action.payload) {
				const { financial_id, checked } = action.payload;
				let selectedFinancials: FinancialsModel[] = state.selectedFinancials || [];
				if (state && state.financialsList) {
					const f = state.financialsList.find(
						(financials) => financials && financials.financials_id === financial_id
					);
					if (state.selectedFinancials) {
						const isinState = state.selectedFinancials.filter(
							(financial) => financial.financials_id === financial_id
						);
						if (isinState.length === 0) {
							selectedFinancials.push(f as FinancialsModel);
						} else {
							// filter out the unchecked financial
							selectedFinancials = state.selectedFinancials.filter(
								(financial) => financial.financials_id !== financial_id
							);
						}
					} else if (checked) {
						selectedFinancials.push(f as FinancialsModel);
					}
				}
				// selectedFinancials.forEach((f, index) => {
				// 	localStorage.setItem(selectedFinancialsIndexes[index], JSON.stringify(f));
				// });
				state.selectedFinancials = sortFinancialRecordsByYearStart(selectedFinancials);
				helperSetFinancialsInLocalStorage(selectedFinancials);
				localStorage.setItem('selectedFinancials', JSON.stringify(selectedFinancials));
			}
		},
		setDemoFinancials: (state, action) => {
			state.financialsList = action.payload;
			state.selectedFinancials = action.payload;
			localStorage.setItem('selectedFinancials', JSON.stringify(action.payload));
		},
		setFinancialItemForEdit: (state, action) => {
			state.editFinancialtemId = action.payload;
		},
		clearFinancialItemForEdit: (state) => {
			state.editFinancialtemId = null;
		}
	},
	extraReducers: (builder) => {
		builder
			.addCase(fetchFinancialsData.pending, (state, action) => {
				state.financialsList = null;
				// state.selectedFinancials = null;
			})
			.addCase(fetchFinancialsData.fulfilled, (state, action) => {
				if (action.payload) {
					const { selectedCompany, financialData } = action.payload;
					state.financialsList = financialData;
					// check if there are preselected financials for this company:
					const selectedFinancialsJSON = localStorage.getItem('selectedFinancials') as string;
					const selectedFinancials =
						selectedFinancialsJSON && selectedFinancialsJSON !== ''
							? JSON.parse(selectedFinancialsJSON as string)
							: null;
					if (selectedFinancials && selectedCompany) {
						// check if preselected financials are still valid for selectedCompany
						const selectedFinancialsForSelectedCompany = (
							selectedFinancials as FinancialsModel[]
						).filter(
							(financial) =>
								(selectedCompany.plan.id === 1 ||
									financial.company_id === selectedCompany.company_id) &&
								state.financialsList?.find((f) => f.financials_id === financial.financials_id)
						);
						// set selected financials to what is already selected in localStorage
						state.selectedFinancials = sortFinancialRecordsByYearStart(
							selectedFinancialsForSelectedCompany
						);
						// update the localStorage with the new selected financials
						if (selectedFinancialsForSelectedCompany.length > 0) {
							localStorage.setItem(
								'selectedFinancials',
								JSON.stringify(selectedFinancialsForSelectedCompany)
							);
						} else {
							console.log(
								'selectedFinancialsForSelectedCompany is empty >> REMOVING FINANCIALS FROM LOCAL STORAGE'
							);
							localStorage.removeItem('selectedFinancials');
							helperClearAllFinancialsInLocalStorage();
						}
					} else {
						// set selected financials to null only if selected company is on paid plan:
						if (selectedCompany && selectedCompany.plan && selectedCompany.plan.id > 1) {
							state.selectedFinancials = null;
							helperClearAllFinancialsInLocalStorage();
						}
					}
				}
			})
			.addCase(patchFinancialsData.fulfilled, (state, action) => {
				if (action.payload) {
					state.editFinancialtemId = null;
					const { financialData } = action.payload;
					// Find the index of the record in state.selectedFinancials where financials_id matches

					let found = false;
					if (state.financialsList && financialData) {
						// found = !!state.financialsList.find((record) => {
						// 	return record.financials_id === financialData.financials_id;
						// });
						// state.financialsList = state.financialsList.map((record) =>
						// 	record.financials_id === financialData.financials_id ? financialData : record
						// );
						state.financialsList = state.financialsList.map((record) => {
							if (record.financials_id === financialData.financials_id) {
								found = true;
								return financialData;
							}
							return record;
						});
					}

					// there could be an instance where we are updating financial data, but there are no selected financials
					if (found) {
						if (state.selectedFinancials && financialData) {
							state.selectedFinancials = sortFinancialRecordsByYearStart(
								state.selectedFinancials.map((record) => {
									if (record.financials_id === financialData.financials_id) {
										found = true;
										return financialData;
									}
									return record;
								})
							);

							// If the record exists in state.selectedFinancials, update it
							if (found) {
								// Update the state and store the updated data in localStorage
								localStorage.setItem(
									'selectedFinancials',
									JSON.stringify(state.selectedFinancials)
								);
							}
							// fail silently as the user has may have not selected the financial that we are updating
							// else {
							// 	throw new Error('Record not found for the given financials_id');
							// }
						}
						// fail silently as the user has not selected any financials yet
						//  else {
						// 	throw new Error('Record not found for the given financials_id');
						// }
					}
				} else {
					throw new Error('No payload found for patchFinancialsData');
				}
			})
			.addCase(insertFinancialsData.fulfilled, (state, action) => {
				if (action.payload) {
					const { financialData } = action.payload;
					if (state.financialsList && financialData) {
						state.financialsList.push(financialData);
					} else if (financialData) {
						state.financialsList = [financialData];
					}
				} else {
					throw new Error('No payload found for insertFinancialsData');
				}
			})
			.addCase(deleteFinancialData.fulfilled, (state, action) => {
				if (action.payload) {
					const { financialData } = action.payload;
					if (state.financialsList && financialData) {
						// Remove the item from financialsList where financials_id matches
						state.financialsList = state.financialsList.filter(
							(item) => item.financials_id !== financialData.financials_id
						);
					}
				} else {
					throw new Error('No payload found for deleteFinancialData');
				}
			});
	}
});

export const fetchFinancialsData = createAsyncThunk(
	'financials/fetchFinancialsData',
	async ({
		selectedCompany,
		planExpired = false
	}: {
		selectedCompany: CompanyDbModel;
		planExpired?: boolean;
	}) => {
		if (selectedCompany.plan.id <= 1 || planExpired) {
			return { selectedCompany, financialData: selectedDemoFinancials };
		}
		// fetch financial data for selected company
		const financialData = await axios
			.get(apiUrl + backendRoutes.financials.get, {
				params: {
					company_id: selectedCompany.company_id
				}
			})
			.then((results: AxiosResponse<FinancialsModel[]>) => results.data as FinancialsModel[])
			.catch((error) => {
				console.error(error.message);
				return null;
			});
		return { selectedCompany, financialData };
	}
);

export const patchFinancialsData = createAsyncThunk(
	'financials/patchFinancialsData',
	async (financialRecordData: any) => {
		if (!financialRecordData.company_id || !financialRecordData.financials_id) {
			// do nothing
			return null;
		}
		// fetch financial data for selected company
		const financialData = await axios
			.post(apiUrl + backendRoutes.financials.post, financialRecordData)
			.then((results: AxiosResponse<FinancialsModel>) => {
				console.log('>>> PATCHING FINANCIALS DATA...', results.data);
				return results.data as FinancialsModel;
			})
			.catch((error) => {
				console.error(error.message);
				return null;
			});
		return { financialData };
	}
);

export const insertFinancialsData = createAsyncThunk(
	'financials/insertFinancialsData',
	async (financialRecordData: any) => {
		if (!financialRecordData.company_id || !financialRecordData.financials_id) {
			// do nothing
			return null;
		}
		// fetch financial data for selected company
		const financialData = await axios
			.post(apiUrl + backendRoutes.financials.post, financialRecordData)
			.then((results: AxiosResponse<FinancialsModel>) => {
				console.log('>>> INSERTING FINANCIALS DATA...', results.data);
				return results.data as FinancialsModel;
			})
			.catch((error) => {
				console.error(error.message);
				return null;
			});
		return { financialData };
	}
);

export const deleteFinancialData = createAsyncThunk(
	'financials/deleteFinancialData',
	async (financialRecordData: any) => {
		if (!financialRecordData.company_id || !financialRecordData.financials_id) {
			// do nothing
			return null;
		}

		// delete financial data for selected company
		try {
			await axios
				.delete(
					`${apiUrl}${backendRoutes.financials.remove}?company_id=${financialRecordData.company_id}&financials_id=${financialRecordData.financials_id}`,
					financialRecordData
				)
				.then((response: AxiosResponse<{ company_id: string }>) => response.data);
			return { financialData: financialRecordData };
		} 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 {
	setSelectedFinancials,
	setSelectedFinancial,
	setDemoFinancials,
	setFinancialItemForEdit,
	clearFinancialItemForEdit
} = financialsSlice.actions;

export default financialsSlice.reducer;
