import { defineStore } from 'pinia';

import { useSettingsStore } from './setting.js';
import { useUserStore } from './user.js';
import { useAccountsStore } from './account.js';
import { useTransactionCategoriesStore } from './transactionCategory.js';
import { useExchangeRatesStore } from './exchangeRates.js';

import datetimeConstants from '@/consts/datetime.js';
import statisticsConstants from '@/consts/statistics.js';
import categoryConstants from '@/consts/category.js';
import iconConstants from '@/consts/icon.js';
import colorConstants from '@/consts/color.js';
import services from '@/lib/services.js';
import logger from '@/lib/logger.js';
import {
    isEquals,
    isNumber,
    isObject,
    isInteger,
    isYearMonth,
    isYearMonthEquals,
    isObjectEmpty,
    objectFieldToArrayItem
} from '@/lib/common.js';
import {
    getYearAndMonthFromUnixTime,
    getDateRangeByDateType
} from '@/lib/datetime.js';
import {
    getFinalAccountIdsByFilteredAccountIds
} from '@/lib/account.js';
import {
    getFinalCategoryIdsByFilteredCategoryIds
} from '@/lib/category.js';
import {
    sortStatisticsItems
} from '@/lib/statistics.js';

function assembleAccountAndCategoryInfo(userStore, accountsStore, transactionCategoriesStore, exchangeRatesStore, items) {
    const finalItems = [];
    const defaultCurrency = userStore.currentUserDefaultCurrency;

    for (let i = 0; i < items.length; i++) {
        const dataItem = items[i];
        const item = {
            categoryId: dataItem.categoryId,
            accountId: dataItem.accountId,
            amount: dataItem.amount
        };

        if (item.accountId) {
            item.account = accountsStore.allAccountsMap[item.accountId];
        }

        if (item.account && item.account.parentId !== '0') {
            item.primaryAccount = accountsStore.allAccountsMap[item.account.parentId];
        } else {
            item.primaryAccount = item.account;
        }

        if (item.categoryId) {
            item.category = transactionCategoriesStore.allTransactionCategoriesMap[item.categoryId];
        }

        if (item.category && item.category.parentId !== '0') {
            item.primaryCategory = transactionCategoriesStore.allTransactionCategoriesMap[item.category.parentId];
        } else {
            item.primaryCategory = item.category;
        }

        if (item.account && item.account.currency !== defaultCurrency) {
            const amount = exchangeRatesStore.getExchangedAmount(item.amount, item.account.currency, defaultCurrency);

            if (isNumber(amount)) {
                item.amountInDefaultCurrency = Math.floor(amount);
            }
        } else if (item.account && item.account.currency === defaultCurrency) {
            item.amountInDefaultCurrency = item.amount;
        } else {
            item.amountInDefaultCurrency = null;
        }

        finalItems.push(item);
    }

    return finalItems;
}

function getCategoryTotalAmountItems(items, transactionStatisticsFilter) {
    const allDataItems = {};
    let totalAmount = 0;
    let totalNonNegativeAmount = 0;

    for (let i = 0; i < items.length; i++) {
        const item = items[i];

        if (!item.primaryAccount || !item.account || !item.primaryCategory || !item.category) {
            continue;
        }

        if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type) {
            if (item.category.type !== categoryConstants.allCategoryTypes.Expense) {
                continue;
            }
        } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type) {
            if (item.category.type !== categoryConstants.allCategoryTypes.Income) {
                continue;
            }
        } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type) {
            // Do Nothing
        } else {
            continue;
        }

        if (transactionStatisticsFilter.filterAccountIds && transactionStatisticsFilter.filterAccountIds[item.account.id]) {
            continue;
        }

        if (transactionStatisticsFilter.filterCategoryIds && transactionStatisticsFilter.filterCategoryIds[item.category.id]) {
            continue;
        }

        if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type) {
            if (isNumber(item.amountInDefaultCurrency)) {
                let data = allDataItems[item.account.id];

                if (data) {
                    data.totalAmount += item.amountInDefaultCurrency;
                } else {
                    data = {
                        name: item.account.name,
                        type: 'account',
                        id: item.account.id,
                        icon: item.account.icon || iconConstants.defaultAccountIcon.icon,
                        color: item.account.color || colorConstants.defaultAccountColor,
                        hidden: item.primaryAccount.hidden || item.account.hidden,
                        displayOrders: [item.primaryAccount.category, item.primaryAccount.displayOrder, item.account.displayOrder],
                        totalAmount: item.amountInDefaultCurrency
                    }
                }

                totalAmount += item.amountInDefaultCurrency;

                if (item.amountInDefaultCurrency > 0) {
                    totalNonNegativeAmount += item.amountInDefaultCurrency;
                }

                allDataItems[item.account.id] = data;
            }
        } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type) {
            if (isNumber(item.amountInDefaultCurrency)) {
                let data = allDataItems[item.primaryCategory.id];

                if (data) {
                    data.totalAmount += item.amountInDefaultCurrency;
                } else {
                    data = {
                        name: item.primaryCategory.name,
                        type: 'category',
                        id: item.primaryCategory.id,
                        icon: item.primaryCategory.icon || iconConstants.defaultCategoryIcon.icon,
                        color: item.primaryCategory.color || colorConstants.defaultCategoryColor,
                        hidden: item.primaryCategory.hidden,
                        displayOrders: [item.primaryCategory.type, item.primaryCategory.displayOrder],
                        totalAmount: item.amountInDefaultCurrency
                    }
                }

                totalAmount += item.amountInDefaultCurrency;

                if (item.amountInDefaultCurrency > 0) {
                    totalNonNegativeAmount += item.amountInDefaultCurrency;
                }

                allDataItems[item.primaryCategory.id] = data;
            }
        } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type) {
            if (isNumber(item.amountInDefaultCurrency)) {
                let data = allDataItems[item.category.id];

                if (data) {
                    data.totalAmount += item.amountInDefaultCurrency;
                } else {
                    data = {
                        name: item.category.name,
                        type: 'category',
                        id: item.category.id,
                        icon: item.category.icon || iconConstants.defaultCategoryIcon.icon,
                        color: item.category.color || colorConstants.defaultCategoryColor,
                        hidden: item.primaryCategory.hidden || item.category.hidden,
                        displayOrders: [item.primaryCategory.type, item.primaryCategory.displayOrder, item.category.displayOrder],
                        totalAmount: item.amountInDefaultCurrency
                    }
                }

                totalAmount += item.amountInDefaultCurrency;

                if (item.amountInDefaultCurrency > 0) {
                    totalNonNegativeAmount += item.amountInDefaultCurrency;
                }

                allDataItems[item.category.id] = data;
            }
        } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type ||
            transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type) {
            if (isNumber(item.amountInDefaultCurrency)) {
                let data = allDataItems['total'];
                let amount = item.amountInDefaultCurrency;

                if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type &&
                    item.category.type === categoryConstants.allCategoryTypes.Expense) {
                    amount = -amount;
                }

                if (data) {
                    data.totalAmount += amount;
                } else {
                    let name = '';

                    if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type) {
                        name = statisticsConstants.allChartDataTypes.TotalExpense.name;
                    } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type) {
                        name = statisticsConstants.allChartDataTypes.TotalIncome.name;
                    } else if (transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalBalance.type) {
                        name = statisticsConstants.allChartDataTypes.TotalBalance.name;
                    }

                    data = {
                        name: name,
                        type: 'total',
                        id: 'total',
                        icon: '',
                        color: '',
                        hidden: false,
                        displayOrders: [1],
                        totalAmount: amount
                    }
                }

                totalAmount += amount;

                if (item.amountInDefaultCurrency > 0) {
                    totalNonNegativeAmount += amount;
                }

                allDataItems['total'] = data;
            }
        }
    }

    return {
        totalAmount: totalAmount,
        totalNonNegativeAmount: totalNonNegativeAmount,
        items: allDataItems
    };
}

function sortCategoryTotalAmountItems(items, transactionStatisticsFilter) {
    sortStatisticsItems(items, transactionStatisticsFilter.sortingType)
}

export const useStatisticsStore = defineStore('statistics', {
    state: () => ({
        transactionStatisticsFilter: {
            chartDataType: statisticsConstants.defaultChartDataType,
            categoricalChartType: statisticsConstants.defaultCategoricalChartType,
            categoricalChartDateType: statisticsConstants.defaultCategoricalChartDataRangeType,
            categoricalChartStartTime: 0,
            categoricalChartEndTime: 0,
            trendChartType: statisticsConstants.defaultTrendChartType,
            trendChartDateType: statisticsConstants.defaultTrendChartDataRangeType,
            trendChartStartYearMonth: '',
            trendChartEndYearMonth: '',
            filterAccountIds: {},
            filterCategoryIds: {}
        },
        transactionCategoryStatisticsData: {},
        transactionCategoryTrendsData: {},
        transactionStatisticsStateInvalid: true
    }),
    getters: {
        categoricalAnalysisChartDataCategory(state) {
            if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalAssets.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
                return 'account';
            } else if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type) {
                return 'category';
            } else {
                return '';
            }
        },
        transactionCategoryStatisticsDataWithCategoryAndAccountInfo(state) {
            const statistics = state.transactionCategoryStatisticsData;
            const finalStatistics = {
                startTime: statistics.startTime,
                endTime: statistics.endTime,
                items: []
            };

            if (statistics && statistics.items && statistics.items.length) {
                const userStore = useUserStore();
                const accountsStore = useAccountsStore();
                const transactionCategoriesStore = useTransactionCategoriesStore();
                const exchangeRatesStore = useExchangeRatesStore();

                finalStatistics.items = assembleAccountAndCategoryInfo(userStore, accountsStore, transactionCategoriesStore, exchangeRatesStore, statistics.items);
            }

            return finalStatistics;
        },
        transactionCategoryTotalAmountAnalysisData(state) {
            if (!state.transactionCategoryStatisticsDataWithCategoryAndAccountInfo || !state.transactionCategoryStatisticsDataWithCategoryAndAccountInfo.items) {
                return null;
            }

            return getCategoryTotalAmountItems(state.transactionCategoryStatisticsDataWithCategoryAndAccountInfo.items, state.transactionStatisticsFilter);
        },
        accountTotalAmountAnalysisData(state) {
            const userStore = useUserStore();
            const accountsStore = useAccountsStore();
            const exchangeRatesStore = useExchangeRatesStore();

            if (!accountsStore.allPlainAccounts) {
                return null;
            }

            const allDataItems = {};
            let totalAmount = 0;
            let totalNonNegativeAmount = 0;

            for (let i = 0; i < accountsStore.allPlainAccounts.length; i++) {
                const account = accountsStore.allPlainAccounts[i];

                if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalAssets.type) {
                    if (!account.isAsset) {
                        continue;
                    }
                } else if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
                    if (!account.isLiability) {
                        continue;
                    }
                }

                if (state.transactionStatisticsFilter.filterAccountIds && state.transactionStatisticsFilter.filterAccountIds[account.id]) {
                    continue;
                }

                let primaryAccount = accountsStore.allAccountsMap[account.parentId];

                if (!primaryAccount) {
                    primaryAccount = account;
                }

                let amount = account.balance;

                if (account.currency !== userStore.currentUserDefaultCurrency) {
                    amount = Math.floor(exchangeRatesStore.getExchangedAmount(amount, account.currency, userStore.currentUserDefaultCurrency));

                    if (!isNumber(amount)) {
                        continue;
                    }
                }

                if (account.isLiability) {
                    amount = -amount;
                }

                const data = {
                    name: account.name,
                    type: 'account',
                    id: account.id,
                    icon: account.icon || iconConstants.defaultAccountIcon.icon,
                    color: account.color || colorConstants.defaultAccountColor,
                    hidden: primaryAccount.hidden || account.hidden,
                    displayOrders: [primaryAccount.category, primaryAccount.displayOrder, account.displayOrder],
                    totalAmount: amount
                };

                totalAmount += amount;

                if (amount > 0) {
                    totalNonNegativeAmount += amount;
                }

                allDataItems[account.id] = data;
            }

            return {
                totalAmount: totalAmount,
                totalNonNegativeAmount: totalNonNegativeAmount,
                items: allDataItems
            }
        },
        categoricalAnalysisData(state) {
            let combinedData = {
                items: [],
                totalAmount: 0
            };

            if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type) {
                combinedData = state.transactionCategoryTotalAmountAnalysisData;
            } else if (state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalAssets.type ||
                state.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
                combinedData = state.accountTotalAmountAnalysisData;
            }

            const allStatisticsItems = [];

            for (let id in combinedData.items) {
                if (!Object.prototype.hasOwnProperty.call(combinedData.items, id)) {
                    continue;
                }

                const data = combinedData.items[id];

                if (data.totalAmount > 0) {
                    data.percent = data.totalAmount * 100 / combinedData.totalNonNegativeAmount;
                } else {
                    data.percent = 0;
                }

                if (data.percent < 0) {
                    data.percent = 0;
                }

                allStatisticsItems.push(data);
            }

            sortCategoryTotalAmountItems(allStatisticsItems, state.transactionStatisticsFilter);

            return {
                totalAmount: combinedData.totalAmount,
                items: allStatisticsItems
            };
        },
        transactionCategoryTrendsDataWithCategoryAndAccountInfo(state) {
            const trendsData = state.transactionCategoryTrendsData;
            const finalTrendsData = [];

            if (trendsData && trendsData.length) {
                const userStore = useUserStore();
                const accountsStore = useAccountsStore();
                const transactionCategoriesStore = useTransactionCategoriesStore();
                const exchangeRatesStore = useExchangeRatesStore();

                for (let i = 0; i < trendsData.length; i++) {
                    const trendItem = trendsData[i];
                    const finalTrendItem = {
                        year: trendItem.year,
                        month: trendItem.month,
                        items: []
                    };

                    if (trendItem && trendItem.items && trendItem.items.length) {
                        finalTrendItem.items = assembleAccountAndCategoryInfo(userStore, accountsStore, transactionCategoriesStore, exchangeRatesStore, trendItem.items);
                    }

                    finalTrendsData.push(finalTrendItem);
                }
            }

            return finalTrendsData;
        },
        trendsAnalysisData(state) {
            if (!state.transactionCategoryTrendsDataWithCategoryAndAccountInfo || !state.transactionCategoryTrendsDataWithCategoryAndAccountInfo.length) {
                return null;
            }

            const combinedDataMap = {};

            for (let i = 0; i < state.transactionCategoryTrendsDataWithCategoryAndAccountInfo.length; i++) {
                const trendItem = state.transactionCategoryTrendsDataWithCategoryAndAccountInfo[i];
                const totalAmountItems = getCategoryTotalAmountItems(trendItem.items, state.transactionStatisticsFilter);

                for (let id in totalAmountItems.items) {
                    if (!Object.prototype.hasOwnProperty.call(totalAmountItems.items, id)) {
                        continue;
                    }

                    const item = totalAmountItems.items[id];
                    let combinedData = combinedDataMap[id];

                    if (!combinedData) {
                        combinedData = {
                            name: item.name,
                            type: item.type,
                            id: item.id,
                            icon: item.icon,
                            color: item.color,
                            hidden: item.hidden,
                            displayOrders: item.displayOrders,
                            totalAmount: 0,
                            items: []
                        };
                    }

                    combinedData.items.push({
                        year: trendItem.year,
                        month: trendItem.month,
                        totalAmount: item.totalAmount
                    });

                    combinedData.totalAmount += item.totalAmount;
                    combinedDataMap[id] = combinedData;
                }
            }

            const totalAmountsTrends = [];

            for (let id in combinedDataMap) {
                if (!Object.prototype.hasOwnProperty.call(combinedDataMap, id)) {
                    continue;
                }

                const trendData = combinedDataMap[id];
                totalAmountsTrends.push(trendData);
            }

            sortCategoryTotalAmountItems(totalAmountsTrends, state.transactionStatisticsFilter);

            return {
                items: totalAmountsTrends
            };
        }
    },
    actions: {
        updateTransactionStatisticsInvalidState(invalidState) {
            this.transactionStatisticsStateInvalid = invalidState;
        },
        resetTransactionStatistics() {
            this.transactionStatisticsFilter.chartDataType = statisticsConstants.defaultChartDataType;
            this.transactionStatisticsFilter.categoricalChartType = statisticsConstants.defaultCategoricalChartType;
            this.transactionStatisticsFilter.categoricalChartDateType = statisticsConstants.defaultCategoricalChartDataRangeType;
            this.transactionStatisticsFilter.categoricalChartStartTime = 0;
            this.transactionStatisticsFilter.categoricalChartEndTime = 0;
            this.transactionStatisticsFilter.trendChartType = statisticsConstants.defaultTrendChartType;
            this.transactionStatisticsFilter.trendChartDateType = statisticsConstants.defaultTrendChartDataRangeType;
            this.transactionStatisticsFilter.trendChartStartYearMonth = '';
            this.transactionStatisticsFilter.trendChartEndYearMonth = '';
            this.transactionStatisticsFilter.filterAccountIds = {};
            this.transactionStatisticsFilter.filterCategoryIds = {};
            this.transactionCategoryStatisticsData = {};
            this.transactionCategoryTrendsData = {};
            this.transactionStatisticsStateInvalid = true;
        },
        initTransactionStatisticsFilter(analysisType, filter) {
            const settingsStore = useSettingsStore();
            const userStore = useUserStore();

            if (filter && isInteger(filter.chartDataType)) {
                this.transactionStatisticsFilter.chartDataType = filter.chartDataType;
            } else {
                this.transactionStatisticsFilter.chartDataType = settingsStore.appSettings.statistics.defaultChartDataType;
            }

            if (analysisType === statisticsConstants.allAnalysisTypes.CategoricalAnalysis || analysisType === statisticsConstants.allAnalysisTypes.TrendAnalysis) {
                if (!statisticsConstants.allChartDataTypesMap[this.transactionStatisticsFilter.chartDataType] ||
                    !statisticsConstants.allChartDataTypesMap[this.transactionStatisticsFilter.chartDataType].availableAnalysisTypes[analysisType]) {
                    this.transactionStatisticsFilter.chartDataType = statisticsConstants.defaultChartDataType;
                }
            }

            if (filter && isInteger(filter.categoricalChartType)) {
                this.transactionStatisticsFilter.categoricalChartType = filter.categoricalChartType;
            } else {
                this.transactionStatisticsFilter.categoricalChartType = settingsStore.appSettings.statistics.defaultCategoricalChartType;
            }

            if (this.transactionStatisticsFilter.categoricalChartType !== statisticsConstants.allCategoricalChartTypes.Pie && this.transactionStatisticsFilter.categoricalChartType !== statisticsConstants.allCategoricalChartTypes.Bar) {
                this.transactionStatisticsFilter.categoricalChartType = statisticsConstants.defaultCategoricalChartType;
            }

            if (filter && isInteger(filter.categoricalChartDateType)) {
                this.transactionStatisticsFilter.categoricalChartDateType = filter.categoricalChartDateType;
            } else {
                this.transactionStatisticsFilter.categoricalChartDateType = settingsStore.appSettings.statistics.defaultCategoricalChartDataRangeType;
            }

            let categoricalChartDateTypeValid = true;

            if (!datetimeConstants.allDateRangesMap[this.transactionStatisticsFilter.categoricalChartDateType] ||
                !datetimeConstants.allDateRangesMap[this.transactionStatisticsFilter.categoricalChartDateType].availableScenes[datetimeConstants.allDateRangeScenes.Normal]) {
                this.transactionStatisticsFilter.categoricalChartDateType = statisticsConstants.defaultCategoricalChartDataRangeType;
                categoricalChartDateTypeValid = false;
            }

            if (categoricalChartDateTypeValid && this.transactionStatisticsFilter.categoricalChartDateType === datetimeConstants.allDateRanges.Custom.type) {
                if (filter && isInteger(filter.categoricalChartStartTime)) {
                    this.transactionStatisticsFilter.categoricalChartStartTime = filter.categoricalChartStartTime;
                } else {
                    this.transactionStatisticsFilter.categoricalChartStartTime = 0;
                }

                if (filter && isInteger(filter.categoricalChartEndTime)) {
                    this.transactionStatisticsFilter.categoricalChartEndTime = filter.categoricalChartEndTime;
                } else {
                    this.transactionStatisticsFilter.categoricalChartEndTime = 0;
                }
            } else {
                const categoricalChartDateRange = getDateRangeByDateType(this.transactionStatisticsFilter.categoricalChartDateType, userStore.currentUserFirstDayOfWeek);
                this.transactionStatisticsFilter.categoricalChartDateType = categoricalChartDateRange.dateType;
                this.transactionStatisticsFilter.categoricalChartStartTime = categoricalChartDateRange.minTime;
                this.transactionStatisticsFilter.categoricalChartEndTime = categoricalChartDateRange.maxTime;
            }

            if (filter && isInteger(filter.trendChartType)) {
                this.transactionStatisticsFilter.trendChartType = filter.trendChartType;
            } else {
                this.transactionStatisticsFilter.trendChartType = settingsStore.appSettings.statistics.defaultTrendChartType;
            }

            if (this.transactionStatisticsFilter.trendChartType !== statisticsConstants.allTrendChartTypes.Area && this.transactionStatisticsFilter.trendChartType !== statisticsConstants.allTrendChartTypes.Column) {
                this.transactionStatisticsFilter.trendChartType = statisticsConstants.defaultTrendChartType;
            }

            if (filter && isInteger(filter.trendChartDateType)) {
                this.transactionStatisticsFilter.trendChartDateType = filter.trendChartDateType;
            } else {
                this.transactionStatisticsFilter.trendChartDateType = settingsStore.appSettings.statistics.defaultTrendChartDataRangeType;
            }

            let trendChartDateTypeValid = true;

            if (!datetimeConstants.allDateRangesMap[this.transactionStatisticsFilter.trendChartDateType] ||
                !datetimeConstants.allDateRangesMap[this.transactionStatisticsFilter.trendChartDateType].availableScenes[datetimeConstants.allDateRangeScenes.TrendAnalysis]) {
                this.transactionStatisticsFilter.trendChartDateType = statisticsConstants.defaultTrendChartDataRangeType;
                trendChartDateTypeValid = false;
            }

            if (trendChartDateTypeValid && this.transactionStatisticsFilter.trendChartDateType === datetimeConstants.allDateRanges.Custom.type) {
                if (filter && isYearMonth(filter.trendChartStartYearMonth)) {
                    this.transactionStatisticsFilter.trendChartStartYearMonth = filter.trendChartStartYearMonth;
                } else {
                    this.transactionStatisticsFilter.trendChartStartYearMonth = '';
                }

                if (filter && isYearMonth(filter.trendChartEndYearMonth)) {
                    this.transactionStatisticsFilter.trendChartEndYearMonth = filter.trendChartEndYearMonth;
                } else {
                    this.transactionStatisticsFilter.trendChartEndYearMonth = '';
                }
            } else {
                const trendChartDateRange = getDateRangeByDateType(this.transactionStatisticsFilter.trendChartDateType, userStore.currentUserFirstDayOfWeek);
                this.transactionStatisticsFilter.trendChartDateType = trendChartDateRange.dateType;
                this.transactionStatisticsFilter.trendChartStartYearMonth = getYearAndMonthFromUnixTime(trendChartDateRange.minTime);
                this.transactionStatisticsFilter.trendChartEndYearMonth = getYearAndMonthFromUnixTime(trendChartDateRange.maxTime);
            }

            if (filter && isObject(filter.filterAccountIds)) {
                this.transactionStatisticsFilter.filterAccountIds = filter.filterAccountIds;
            } else {
                this.transactionStatisticsFilter.filterAccountIds = settingsStore.appSettings.statistics.defaultAccountFilter || {};
            }

            if (filter && isObject(filter.filterCategoryIds)) {
                this.transactionStatisticsFilter.filterCategoryIds = filter.filterCategoryIds;
            } else {
                this.transactionStatisticsFilter.filterCategoryIds = settingsStore.appSettings.statistics.defaultTransactionCategoryFilter || {};
            }

            if (filter && isInteger(filter.sortingType)) {
                this.transactionStatisticsFilter.sortingType = filter.sortingType;
            } else {
                this.transactionStatisticsFilter.sortingType = settingsStore.appSettings.statistics.defaultSortingType;
            }

            if (this.transactionStatisticsFilter.sortingType < statisticsConstants.allSortingTypes.Amount.type || this.transactionStatisticsFilter.sortingType > statisticsConstants.allSortingTypes.Name.type) {
                this.transactionStatisticsFilter.sortingType = statisticsConstants.defaultSortingType;
            }
        },
        updateTransactionStatisticsFilter(filter) {
            let changed = false;

            if (filter && isInteger(filter.chartDataType) && this.transactionStatisticsFilter.chartDataType !== filter.chartDataType) {
                this.transactionStatisticsFilter.chartDataType = filter.chartDataType;
                changed = true;
            }

            if (filter && isInteger(filter.categoricalChartType) && this.transactionStatisticsFilter.categoricalChartType !== filter.categoricalChartType) {
                this.transactionStatisticsFilter.categoricalChartType = filter.categoricalChartType;
                changed = true;
            }

            if (filter && isInteger(filter.categoricalChartDateType) && this.transactionStatisticsFilter.categoricalChartDateType !== filter.categoricalChartDateType) {
                this.transactionStatisticsFilter.categoricalChartDateType = filter.categoricalChartDateType;
                changed = true;
            }

            if (filter && isInteger(filter.categoricalChartStartTime) && this.transactionStatisticsFilter.categoricalChartStartTime !== filter.categoricalChartStartTime) {
                this.transactionStatisticsFilter.categoricalChartStartTime = filter.categoricalChartStartTime;
                changed = true;
            }

            if (filter && isInteger(filter.categoricalChartEndTime) && this.transactionStatisticsFilter.categoricalChartEndTime !== filter.categoricalChartEndTime) {
                this.transactionStatisticsFilter.categoricalChartEndTime = filter.categoricalChartEndTime;
                changed = true;
            }

            if (filter && isInteger(filter.trendChartType) && this.transactionStatisticsFilter.trendChartType !== filter.trendChartType) {
                this.transactionStatisticsFilter.trendChartType = filter.trendChartType;
                changed = true;
            }

            if (filter && isInteger(filter.trendChartDateType) && this.transactionStatisticsFilter.trendChartDateType !== filter.trendChartDateType) {
                this.transactionStatisticsFilter.trendChartDateType = filter.trendChartDateType;
                changed = true;
            }

            if (filter && (isYearMonth(filter.trendChartStartYearMonth) || filter.trendChartStartYearMonth === '') && !isYearMonthEquals(this.transactionStatisticsFilter.trendChartStartYearMonth, filter.trendChartStartYearMonth)) {
                this.transactionStatisticsFilter.trendChartStartYearMonth = filter.trendChartStartYearMonth;
                changed = true;
            }

            if (filter && (isYearMonth(filter.trendChartEndYearMonth) || filter.trendChartEndYearMonth === '') && !isYearMonthEquals(this.transactionStatisticsFilter.trendChartEndYearMonth, filter.trendChartEndYearMonth)) {
                this.transactionStatisticsFilter.trendChartEndYearMonth = filter.trendChartEndYearMonth;
                changed = true;
            }

            if (filter && isObject(filter.filterAccountIds) && !isEquals(this.transactionStatisticsFilter.filterAccountIds, filter.filterAccountIds)) {
                this.transactionStatisticsFilter.filterAccountIds = filter.filterAccountIds;
                changed = true;
            }

            if (filter && isObject(filter.filterCategoryIds) && !isEquals(this.transactionStatisticsFilter.filterCategoryIds, filter.filterCategoryIds)) {
                this.transactionStatisticsFilter.filterCategoryIds = filter.filterCategoryIds;
                changed = true;
            }

            if (filter && isInteger(filter.sortingType) && this.transactionStatisticsFilter.sortingType !== filter.sortingType) {
                this.transactionStatisticsFilter.sortingType = filter.sortingType;
                changed = true;
            }

            return changed;
        },
        getTransactionStatisticsPageParams(analysisType) {
            const querys = [];

            querys.push('analysisType=' + analysisType);
            querys.push('chartDataType=' + this.transactionStatisticsFilter.chartDataType);

            if (analysisType === statisticsConstants.allAnalysisTypes.CategoricalAnalysis) {
                querys.push('chartType=' + this.transactionStatisticsFilter.categoricalChartType);
                querys.push('chartDateType=' + this.transactionStatisticsFilter.categoricalChartDateType);

                if (this.transactionStatisticsFilter.categoricalChartDateType === datetimeConstants.allDateRanges.Custom.type) {
                    querys.push('startTime=' + this.transactionStatisticsFilter.categoricalChartStartTime);
                    querys.push('endTime=' + this.transactionStatisticsFilter.categoricalChartEndTime);
                }
            } else if (analysisType === statisticsConstants.allAnalysisTypes.TrendAnalysis) {
                querys.push('chartType=' + this.transactionStatisticsFilter.trendChartType);
                querys.push('chartDateType=' + this.transactionStatisticsFilter.trendChartDateType);

                if (this.transactionStatisticsFilter.trendChartDateType === datetimeConstants.allDateRanges.Custom.type) {
                    querys.push('startTime=' + this.transactionStatisticsFilter.trendChartStartYearMonth);
                    querys.push('endTime=' + this.transactionStatisticsFilter.trendChartEndYearMonth);
                }
            }

            if (this.transactionStatisticsFilter.filterAccountIds) {
                const ids = objectFieldToArrayItem(this.transactionStatisticsFilter.filterAccountIds);

                if (ids && ids.length) {
                    querys.push('filterAccountIds=' + ids.join(','));
                }
            }

            if (this.transactionStatisticsFilter.filterCategoryIds) {
                const ids = objectFieldToArrayItem(this.transactionStatisticsFilter.filterCategoryIds);

                if (ids && ids.length) {
                    querys.push('filterCategoryIds=' + ids.join(','));
                }
            }

            querys.push('sortingType=' + this.transactionStatisticsFilter.sortingType);

            return querys.join('&');
        },
        getTransactionListPageParams(analysisType, item, dateRange) {
            const accountsStore = useAccountsStore();
            const transactionCategoriesStore = useTransactionCategoriesStore();
            const querys = [];

            if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalIncome.type) {
                querys.push('type=2');
            } else if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.TotalExpense.type) {
                querys.push('type=3');
            }

            if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByAccount.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByAccount.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalAssets.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
                querys.push('accountIds=' + item.id);

                if (!isObjectEmpty(this.transactionStatisticsFilter.filterCategoryIds)) {
                    querys.push('categoryIds=' + getFinalCategoryIdsByFilteredCategoryIds(transactionCategoriesStore.allTransactionCategoriesMap, this.transactionStatisticsFilter.filterCategoryIds));
                }
            } else if (this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeByPrimaryCategory.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.IncomeBySecondaryCategory.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseByPrimaryCategory.type
                || this.transactionStatisticsFilter.chartDataType === statisticsConstants.allChartDataTypes.ExpenseBySecondaryCategory.type) {
                querys.push('categoryIds=' + item.id);

                if (!isObjectEmpty(this.transactionStatisticsFilter.filterAccountIds)) {
                    querys.push('accountIds=' + getFinalAccountIdsByFilteredAccountIds(accountsStore.allAccountsMap, this.transactionStatisticsFilter.filterAccountIds));
                }
            }

            if (analysisType === statisticsConstants.allAnalysisTypes.CategoricalAnalysis
                && this.transactionStatisticsFilter.chartDataType !== statisticsConstants.allChartDataTypes.AccountTotalAssets.type
                && this.transactionStatisticsFilter.chartDataType !== statisticsConstants.allChartDataTypes.AccountTotalLiabilities.type) {
                querys.push('dateType=' + this.transactionStatisticsFilter.categoricalChartDateType);

                if (this.transactionStatisticsFilter.categoricalChartDateType === datetimeConstants.allDateRanges.Custom.type) {
                    querys.push('minTime=' + this.transactionStatisticsFilter.categoricalChartStartTime);
                    querys.push('maxTime=' + this.transactionStatisticsFilter.categoricalChartEndTime);
                }
            } else if (analysisType === statisticsConstants.allAnalysisTypes.TrendAnalysis && dateRange) {
                querys.push('dateType=' + dateRange.type);
                querys.push('minTime=' + dateRange.minTime);
                querys.push('maxTime=' + dateRange.maxTime);
            }

            return querys.join('&');
        },
        loadCategoricalAnalysis({ force }) {
            const self = this;
            const settingsStore = useSettingsStore();

            return new Promise((resolve, reject) => {
                services.getTransactionStatistics({
                    startTime: self.transactionStatisticsFilter.categoricalChartStartTime,
                    endTime: self.transactionStatisticsFilter.categoricalChartEndTime,
                    useTransactionTimezone: settingsStore.appSettings.statistics.defaultTimezoneType
                }).then(response => {
                    const data = response.data;

                    if (!data || !data.success || !data.result) {
                        reject({ message: 'Unable to retrieve transaction statistics' });
                        return;
                    }

                    if (self.transactionStatisticsStateInvalid) {
                        self.updateTransactionStatisticsInvalidState(false);
                    }

                    if (force && data.result && isEquals(self.transactionCategoryStatisticsData, data.result)) {
                        reject({ message: 'Data is up to date' });
                        return;
                    }

                    self.transactionCategoryStatisticsData = data.result;

                    resolve(data.result);
                }).catch(error => {
                    logger.error('failed to retrieve transaction statistics', error);

                    if (error.response && error.response.data && error.response.data.errorMessage) {
                        reject({ error: error.response.data });
                    } else if (!error.processed) {
                        reject({ message: 'Unable to retrieve transaction statistics' });
                    } else {
                        reject(error);
                    }
                });
            });
        },
        loadTrendAnalysis({ force }) {
            const self = this;
            const settingsStore = useSettingsStore();

            return new Promise((resolve, reject) => {
                services.getTransactionStatisticsTrends({
                    startYearMonth: self.transactionStatisticsFilter.trendChartStartYearMonth,
                    endYearMonth: self.transactionStatisticsFilter.trendChartEndYearMonth,
                    useTransactionTimezone: settingsStore.appSettings.statistics.defaultTimezoneType
                }).then(response => {
                    const data = response.data;

                    if (!data || !data.success || !data.result) {
                        reject({ message: 'Unable to retrieve transaction statistics' });
                        return;
                    }

                    if (self.transactionStatisticsStateInvalid) {
                        self.updateTransactionStatisticsInvalidState(false);
                    }

                    if (force && data.result && isEquals(self.transactionCategoryTrendsData, data.result)) {
                        reject({ message: 'Data is up to date' });
                        return;
                    }

                    self.transactionCategoryTrendsData = data.result;

                    resolve(data.result);
                }).catch(error => {
                    logger.error('failed to retrieve transaction statistics', error);

                    if (error.response && error.response.data && error.response.data.errorMessage) {
                        reject({ error: error.response.data });
                    } else if (!error.processed) {
                        reject({ message: 'Unable to retrieve transaction statistics' });
                    } else {
                        reject(error);
                    }
                });
            });
        },
    }
});
