/* eslint-disable react/destructuring-assignment */
import type { ReactNode } from 'react';
import type React from 'react';
import { createContext, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';

import type { CompanyDbModel } from '../../../Pages/Companies/Components/CompaniesComponents.helper';
import type { FinancialsModel } from '../../../Pages/Financials/Components/FinancialsForm/FinancialsForm.helper';
import type { RootState } from '../../../ReduxState/store';

export type FundingMetersModel = {
	netDebtFirst: string;
	netDebtSecond: string;
	netDebtChange: string;
	netCashFlowFirst: string;
	calculatedCashFlowSecond: number;
	netCashFlowSecond: string;
	netCashFlowChange: string;
	debtToEquityFirst: string;
	debtToEquitySecond: string;
	debtToEquityChange: string;
	revenueVariance: string;
	revenueFirst: string;
	cashFromCustomers: string;
	thirdFinancialYear: string;
	directCost: string;
	cashToSupplier: string;
	cashToSupplierVariance: string;
	grossMargin: string;
	grossProfit: string;
	grossProfitVariance: string;
	overheadsExcluded: string;
	overheadsExcludedVariance: string;
	operatingCashProfit: string;
	operatingCashFlow: string;
	operatingCashFlowVariance: string;
	thirdFinancialEbit: string;
	thirdFinancialNetProfitAftrerTax: string;
	workingCapitalChange: string;
	workingCapitalChangeNumber: number;
	surplusSum: string;
	capitalInvested: string;
};

export const FundingMeters: React.Context<FundingMetersModel> = createContext<FundingMetersModel>({
	netDebtFirst: '',
	netDebtSecond: '',
	netDebtChange: '',
	netCashFlowFirst: '',
	calculatedCashFlowSecond: 0,
	netCashFlowSecond: '',
	netCashFlowChange: '',
	debtToEquityFirst: '',
	debtToEquitySecond: '',
	debtToEquityChange: '',
	revenueVariance: '',
	revenueFirst: '',
	cashFromCustomers: '',
	thirdFinancialYear: '',
	directCost: '',
	cashToSupplier: '',
	cashToSupplierVariance: '',
	grossMargin: '',
	grossProfit: '',
	grossProfitVariance: '',
	overheadsExcluded: '',
	overheadsExcludedVariance: '',
	operatingCashProfit: '',
	operatingCashFlow: '',
	operatingCashFlowVariance: '',
	thirdFinancialEbit: '',
	thirdFinancialNetProfitAftrerTax: '',
	workingCapitalChange: '',
	workingCapitalChangeNumber: 0,
	surplusSum: '',
	capitalInvested: ''
});

const FundingMetersProvider: React.FC<{ children: ReactNode }> = (props: {
	children: ReactNode;
}) => {
	// TOREVIEW:
	// looks like these variables could all be replaced by a single object
	// and you could handle them with a single useState
	// it would provide for much better readability
	const [netDebtFirst, setNetDebtFirst] = useState<string>('');
	const [netDebtSecond, setNetDebtSecond] = useState<string>('');
	const [netDebtChange, setNetDebtChange] = useState<string>('');
	const [netCashFlowFirst, setNetCashFlowFirst] = useState<string>('');
	const [calculatedCashFlowSecond, setCalculatedCashFlowSecond] = useState<number>(0);
	const [netCashFlowSecond, setNetCashFlowSecond] = useState<string>('');
	const [netCashFlowChange, setNetCashFlowChange] = useState<string>('');
	const [debtToEquityFirst, setDebtToEquityFirst] = useState<string>('');
	const [debtToEquitySecond, setDebtToEquitySecond] = useState<string>('');
	const [debtToEquityChange, setDebtToEquityChange] = useState<string>('');
	const [revenueVariance, setRevenueVariance] = useState<string>('');
	const [revenueFirst, setRevenueFirst] = useState<string>('');
	const [cashFromCustomers, setCashFromCustomers] = useState<string>('');
	const [thirdFinancialYear, setThirdFinancialYear] = useState<string>('');
	const [directCost, setDirectCost] = useState<string>('');
	const [cashToSupplier, setCashToSupplier] = useState<string>('');
	const [cashToSupplierVariance, setCashToSupplierVariance] = useState<string>('');
	const [grossMargin, setGrossMargin] = useState<string>('');
	const [grossProfit, setGrossProfit] = useState<string>('');
	const [grossProfitVariance, setGrossProfitVariance] = useState<string>('');
	const [overheadsExcluded, setOverheadsExcluded] = useState<string>('');
	const [overheadsExcludedVariance, setOverheadsExcludedVariance] = useState<string>('');
	const [operatingCashProfit, setOperatingCashProfit] = useState<string>('');
	const [operatingCashFlow, setOperatingCashFlow] = useState<string>('');
	const [operatingCashFlowVariance, setOperatingCashFlowVariance] = useState<string>('');
	const [thirdFinancialEbit, setThirdFinancialEbit] = useState<string>('');
	const [thirdFinancialNetProfitAftrerTax, setThirdFinancialNetProfitAftrerTax] =
		useState<string>('');
	const [workingCapitalChange, setWorkingCapitalChange] = useState<string>('');
	const [workingCapitalChangeNumber, setWorkingCapitalChangeNumber] = useState<number>(0);
	const [surplusSum, setSurplusSum] = useState<string>('');
	const [capitalInvested, setCapitalInvested] = useState<string>('');
	const selectedCompany = useSelector(
		(state: RootState): CompanyDbModel | null => state.companies.selectedCompany
	);
	const [currencyLabel, setCurrencyLabel] = useState<string>('GBP');
	useEffect(() => {
		if (selectedCompany) {
			setCurrencyLabel(
				`${
					typeof selectedCompany?.currency_symbol === 'string'
						? 'GBP'
						: selectedCompany?.currency_symbol.value
				}`
			);
		}
	}, [selectedCompany]);

	function fundingMeterCalculations(): void {
		const firstFinancial: FinancialsModel = JSON.parse(
			localStorage.getItem('first-financial') as string
		);
		const secondFinancial: FinancialsModel = JSON.parse(
			localStorage.getItem('second-financial') as string
		);
		const thirdFinancial: FinancialsModel = JSON.parse(
			localStorage.getItem('third-financial') as string
		);
		const calculatedNetDebtFirst =
			+secondFinancial.input['Additional Bank Loans - Current'] +
			+secondFinancial.input['Additional Bank Loans - Non Current'] -
			+secondFinancial.input['Cash at Bank'];
		const calculatedNetDebtSecond =
			+thirdFinancial.input['Additional Bank Loans - Current'] +
			+thirdFinancial.input['Additional Bank Loans - Non Current'] -
			+thirdFinancial.input['Cash at Bank'];
		const calculatedNetDebtChange =
			((calculatedNetDebtSecond - calculatedNetDebtFirst) / calculatedNetDebtFirst) * 100;
		const calculatedCashFlowFirst =
			-(
				+firstFinancial.input['Cash at Bank'] -
				(+firstFinancial.input['Additional Bank Loans - Current'] +
					+firstFinancial.input['Additional Bank Loans - Non Current'])
			) -
			-(
				+secondFinancial.input['Cash at Bank'] -
				(+secondFinancial.input['Additional Bank Loans - Current'] +
					+secondFinancial.input['Additional Bank Loans - Non Current'])
			);
		const calculatedCashFlowSecond =
			-(
				+secondFinancial.input['Cash at Bank'] -
				(+secondFinancial.input['Additional Bank Loans - Current'] +
					+secondFinancial.input['Additional Bank Loans - Non Current'])
			) -
			-(
				+thirdFinancial.input['Cash at Bank'] -
				(+thirdFinancial.input['Additional Bank Loans - Current'] +
					+thirdFinancial.input['Additional Bank Loans - Non Current'])
			);
		const calculatedCashFlowChange =
			((calculatedCashFlowSecond - calculatedCashFlowFirst) / calculatedCashFlowFirst) * 100;

		const calculatedDebtToEquityFirst =
			(+secondFinancial.input['Additional Bank Loans - Current'] +
				+secondFinancial.input['Additional Bank Loans - Non Current']) /
			(+secondFinancial.input['Additional Total Assets'] -
				+secondFinancial.input['Additional Total Liabilities']);
		const calculatedDebtToEquitySecond =
			(+thirdFinancial.input['Additional Bank Loans - Current'] +
				+thirdFinancial.input['Additional Bank Loans - Non Current']) /
			(+thirdFinancial.input['Additional Total Assets'] -
				+thirdFinancial.input['Additional Total Liabilities']);
		const calculatedDebtToEquityChange =
			calculatedDebtToEquitySecond === 0 || calculatedDebtToEquityFirst === 0
				? 0
				: ((calculatedDebtToEquitySecond - +calculatedDebtToEquityFirst) /
						+calculatedDebtToEquityFirst) *
				  100;

		const calculatedRevenue = +thirdFinancial.input.Revenue;
		const calculatedCashFromCustomersVariance =
			+secondFinancial.input['Trade Debtors'] - +thirdFinancial.input['Trade Debtors'];
		const calculatedCashFromCustomers = calculatedRevenue + calculatedCashFromCustomersVariance;
		const directCostDefined = +thirdFinancial.input.COGS;
		const calculatedCashToSuppliersVariance =
			+secondFinancial.input['Trade Creditors'] -
			+thirdFinancial.input['Trade Creditors'] +
			(+thirdFinancial.input.Stock - +secondFinancial.input.Stock);
		console.log(
			'cash to suppliers variance calc',
			+thirdFinancial.input['Trade Creditors'],
			+secondFinancial.input['Trade Creditors'],
			+secondFinancial.input.Stock,
			+thirdFinancial.input.Stock
		);
		console.log('cash to suppliers variance', calculatedCashToSuppliersVariance);
		const calculatedCashToSuppliers = directCostDefined + calculatedCashToSuppliersVariance;
		const calculatedGrossMargin = +calculatedRevenue - +directCostDefined;
		const calculatedGrossProfit = +calculatedCashFromCustomers - +calculatedCashToSuppliers;
		const calculatedGrossProfitVariance = calculatedGrossProfit - calculatedGrossMargin;
		const calculatedOverheadsExcluded =
			+thirdFinancial.input['Gross Profit'] -
			+thirdFinancial.input.EBIT -
			+thirdFinancial.input.Depreciation;
		const calculatedOverheadsExcludedVariance =
			calculatedOverheadsExcluded - calculatedOverheadsExcluded;

		const calculatedOperatingCashProfit = +calculatedGrossMargin - +calculatedOverheadsExcluded;
		const calculatedOperatingCashFlow = +calculatedGrossProfit - +calculatedOverheadsExcluded;
		const calculatedOperatingCashFlowVariance =
			calculatedOperatingCashFlow - calculatedOperatingCashProfit;
		const definedThirdFinancialEbit = +thirdFinancial.input.EBIT;
		const definedThirdFinancialNetProfitAftrerTax = +thirdFinancial.input['Net Profit'];
		const calculatedWorkingCapitalChange =
			+secondFinancial.input['Trade Debtors'] +
			+secondFinancial.input.Stock -
			+secondFinancial.input['Trade Creditors'] -
			+secondFinancial.input['Deferred Revenue'] -
			(+thirdFinancial.input['Trade Debtors'] +
				+thirdFinancial.input.Stock -
				+thirdFinancial.input['Trade Creditors'] -
				+thirdFinancial.input['Deferred Revenue']);
		const calculatedCapitalInvested =
			+thirdFinancial.input['Additional Total Assets'] -
			+thirdFinancial.input['Additional Total Liabilities'] -
			(+secondFinancial.input['Additional Total Assets'] -
				+secondFinancial.input['Additional Total Liabilities']) +
			+thirdFinancial.input.Dividends -
			+thirdFinancial.input['Net Profit'];

		// TOREVIEW:
		// you should always keep the values of type number
		// they should be formatted only on presentation layer
		// otherwise what you end up with is constantly converting (like above) to number
		// affecting both the readability of code and performance of the application
		setNetDebtFirst(
			calculatedNetDebtFirst.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setNetDebtSecond(
			calculatedNetDebtSecond.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setNetDebtChange(calculatedNetDebtChange.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'));
		setNetCashFlowFirst(
			calculatedCashFlowFirst.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setNetCashFlowSecond(
			calculatedCashFlowSecond.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		console.log('setting calccashflowsecond', calculatedCashFlowSecond);
		setCalculatedCashFlowSecond(calculatedCashFlowSecond);
		setNetCashFlowChange(
			calculatedCashFlowChange.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
		);
		setDebtToEquityFirst(
			calculatedDebtToEquityFirst.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
		);
		setDebtToEquitySecond(
			calculatedDebtToEquitySecond.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
		);
		setDebtToEquityChange(
			calculatedDebtToEquityChange.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,')
		);
		setRevenueVariance(
			calculatedCashFromCustomersVariance.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setRevenueFirst(
			calculatedRevenue.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setCashFromCustomers(
			calculatedCashFromCustomers.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setThirdFinancialYear(thirdFinancial.input['Year Ending']);
		setDirectCost(
			directCostDefined.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setCashToSupplier(
			calculatedCashToSuppliers.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setCashToSupplierVariance(
			calculatedCashToSuppliersVariance.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setGrossMargin(
			calculatedGrossMargin.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setGrossProfit(
			calculatedGrossProfit.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setGrossProfitVariance(
			calculatedGrossProfitVariance.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setOverheadsExcluded(
			calculatedOverheadsExcluded.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setOverheadsExcludedVariance(
			calculatedOverheadsExcludedVariance.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setOperatingCashProfit(
			calculatedOperatingCashProfit.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setOperatingCashFlow(
			calculatedOperatingCashFlow.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setOperatingCashFlowVariance(
			calculatedOperatingCashFlowVariance.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setThirdFinancialEbit(
			definedThirdFinancialEbit.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setThirdFinancialNetProfitAftrerTax(
			definedThirdFinancialNetProfitAftrerTax.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setWorkingCapitalChange(
			calculatedWorkingCapitalChange.toLocaleString('en-GB', {
				style: 'currency',
				currency: currencyLabel,
				minimumFractionDigits: 0,
				maximumFractionDigits: 0
			})
		);
		setWorkingCapitalChangeNumber(calculatedWorkingCapitalChange);
		setSurplusSum(
			(+definedThirdFinancialNetProfitAftrerTax + +calculatedWorkingCapitalChange)
				.toFixed(0)
				.toString()
		);
		setCapitalInvested(calculatedCapitalInvested.toFixed(0).toString());
	}

	useEffect(() => {
		window.scrollTo(0, 0);
		const firstFinancial: FinancialsModel = JSON.parse(
			localStorage.getItem('first-financial') as string
		);
		const secondFinancial: FinancialsModel = JSON.parse(
			localStorage.getItem('second-financial') as string
		);
		const thirdFinancial: FinancialsModel = JSON.parse(
			localStorage.getItem('third-financial') as string
		);
		if (
			firstFinancial &&
			secondFinancial &&
			thirdFinancial &&
			firstFinancial.input !== undefined &&
			secondFinancial.input !== undefined &&
			thirdFinancial.input !== undefined
		) {
			fundingMeterCalculations();
		}
	}, []);

	// eslint-disable-next-line react/jsx-no-constructed-context-values
	const contextValue = {
		netDebtFirst,
		netDebtSecond,
		netDebtChange,
		netCashFlowFirst,
		calculatedCashFlowSecond,
		netCashFlowSecond,
		netCashFlowChange,
		debtToEquityFirst,
		debtToEquitySecond,
		debtToEquityChange,
		revenueVariance,
		revenueFirst,
		cashFromCustomers,
		thirdFinancialYear,
		directCost,
		cashToSupplier,
		cashToSupplierVariance,
		grossMargin,
		grossProfit,
		grossProfitVariance,
		overheadsExcluded,
		overheadsExcludedVariance,
		operatingCashProfit,
		operatingCashFlow,
		operatingCashFlowVariance,
		thirdFinancialEbit,
		thirdFinancialNetProfitAftrerTax,
		workingCapitalChange,
		workingCapitalChangeNumber,
		surplusSum,
		capitalInvested
	};
	return <FundingMeters.Provider value={contextValue}>{props.children}</FundingMeters.Provider>;
};

export default FundingMetersProvider;
