import React, { useEffect, useEffectEvent, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { useLocation, useParams } from 'react-router';

import { AlignedText } from '@actual-app/components/aligned-text';
import { Block } from '@actual-app/components/block';
import { useResponsive } from '@actual-app/components/hooks/useResponsive';
import { styles } from '@actual-app/components/styles';
import { Text } from '@actual-app/components/text';
import { theme } from '@actual-app/components/theme';
import { View } from '@actual-app/components/view';
import { send } from '@actual-app/core/platform/client/connection';
import * as monthUtils from '@actual-app/core/shared/months';
import type {
  balanceTypeOpType,
  CategoryEntity,
  CustomReportEntity,
  DataEntity,
  RuleConditionEntity,
  sortByOpType,
  TransactionEntity,
} from '@actual-app/core/types/models';
import type { SyncedPrefs } from '@actual-app/core/types/prefs';
import type { TransObjectLiteral } from '@actual-app/core/types/util';
import * as d from 'date-fns';

import { Warning } from '#components/alerts';
import { AppliedFilters } from '#components/filters/AppliedFilters';
import { FinancialText } from '#components/FinancialText';
import { MobileBackButton } from '#components/mobile/MobileBackButton';
import { MobilePageHeader, Page, PageHeader } from '#components/Page';
import { PrivacyFilter } from '#components/PrivacyFilter';
import { ChooseGraph } from '#components/reports/ChooseGraph';
import {
  defaultsGraphList,
  defaultsList,
  disabledGraphList,
  disabledLegendLabel,
  disabledList,
} from '#components/reports/disabledList';
import { getLiveRange } from '#components/reports/getLiveRange';
import { LoadingIndicator } from '#components/reports/LoadingIndicator';
import { ReportLegend } from '#components/reports/ReportLegend';
import {
  defaultReport,
  ReportOptions,
} from '#components/reports/ReportOptions';
import type { dateRangeProps } from '#components/reports/ReportOptions';
import { ReportSidebar } from '#components/reports/ReportSidebar';
import { ReportSummary } from '#components/reports/ReportSummary';
import { ReportTopbar } from '#components/reports/ReportTopbar';
import type { SavedStatus } from '#components/reports/SaveReportMenu';
import { setSessionReport } from '#components/reports/setSessionReport';
import { createCustomSpreadsheet } from '#components/reports/spreadsheets/custom-spreadsheet';
import { createGroupedSpreadsheet } from '#components/reports/spreadsheets/grouped-spreadsheet';
import { useReport } from '#components/reports/useReport';
import { calculateHasWarning, fromDateRepr } from '#components/reports/util';
import { useAccounts } from '#hooks/useAccounts';
import { useCategories } from '#hooks/useCategories';
import { useFormat } from '#hooks/useFormat';
import { useLocale } from '#hooks/useLocale';
import { useLocalPref } from '#hooks/useLocalPref';
import { useNavigate } from '#hooks/useNavigate';
import { usePayees } from '#hooks/usePayees';
import { useReport as useCustomReport } from '#hooks/useReport';
import { useRuleConditionFilters } from '#hooks/useRuleConditionFilters';
import { useSyncedPref } from '#hooks/useSyncedPref';

/**
 * Transform `selectedCategories` into `conditions`.
 */
function useSelectedCategories(
  conditions: RuleConditionEntity[],
  categories: CategoryEntity[],
): CategoryEntity[] {
  const existingCategoryCondition = useMemo(
    () => conditions.find(({ field }) => field === 'category'),
    [conditions],
  );

  return useMemo(() => {
    if (!existingCategoryCondition) {
      return categories;
    }

    switch (existingCategoryCondition.op) {
      case 'is':
        return categories.filter(
          ({ id }) => id === existingCategoryCondition.value,
        );

      case 'isNot':
        return categories.filter(
          ({ id }) => existingCategoryCondition.value !== id,
        );

      case 'oneOf':
        return categories.filter(({ id }) =>
          existingCategoryCondition.value.includes(id),
        );

      case 'notOneOf':
        return categories.filter(
          ({ id }) => !existingCategoryCondition.value.includes(id),
        );

      default:
        break;
    }

    return categories;
  }, [existingCategoryCondition, categories]);
}

const BUDGETED_SUPPORTED_CONDITION_FIELDS = new Set<
  RuleConditionEntity['field']
>(['category']);

export function CustomReport() {
  const params = useParams();
  const { data: report, isPending } = useCustomReport(params.id);
  const [budgetType = 'envelope'] = useSyncedPref('budgetType');

  if (isPending) {
    return <LoadingIndicator />;
  }

  return (
    <CustomReportInner
      key={report?.id}
      report={report}
      budgetType={budgetType}
    />
  );
}

type CustomReportInnerProps = {
  report?: CustomReportEntity;
  budgetType: SyncedPrefs['budgetType'];
};

function CustomReportInner({
  report: initialReport,
  budgetType,
}: CustomReportInnerProps) {
  const locale = useLocale();
  const { t } = useTranslation();
  const format = useFormat();

  const { data: categories = { grouped: [], list: [] } } = useCategories();
  const { isNarrowWidth } = useResponsive();
  const [_firstDayOfWeekIdx] = useSyncedPref('firstDayOfWeekIdx');
  const firstDayOfWeekIdx = _firstDayOfWeekIdx || '0';

  const [viewLegend = false, setViewLegendPref] =
    useLocalPref('reportsViewLegend');
  const [viewSummary = false, setViewSummaryPref] =
    useLocalPref('reportsViewSummary');
  const [viewLabels = false, setViewLabelsPref] =
    useLocalPref('reportsViewLabel');

  const {
    conditions,
    conditionsOp,
    onApply: onApplyFilter,
    onDelete: onDeleteFilter,
    onUpdate: onUpdateFilter,
    onConditionsOpChange,
  } = useRuleConditionFilters();

  const location = useLocation();

  const prevUrl = sessionStorage.getItem('url') || '';

  sessionStorage.setItem('prevUrl', prevUrl);
  sessionStorage.setItem('url', location.pathname);

  if (prevUrl !== location.pathname) sessionStorage.clear();

  const reportFromSessionStorage = sessionStorage.getItem('report');
  const session: Partial<CustomReportEntity> = reportFromSessionStorage
    ? JSON.parse(reportFromSessionStorage)
    : {};
  const combine = initialReport ?? defaultReport;

  const loadReport: CustomReportEntity = {
    ...combine,
    ...session,
  };

  const [allIntervals, setAllIntervals] = useState<
    Array<{
      name: string;
      pretty: string;
    }>
  >([]);

  // Complex category conditions are:
  // - conditions with multiple "category" fields
  // - conditions with "category" field that use "contains", "doesNotContain", "matches", "hasTags" operations
  // - conditions with a "category_group" field
  const isComplexCategoryCondition =
    !!conditions.find(
      ({ field, op }) =>
        field === 'category' &&
        [
          'contains',
          'doesNotContain',
          'matches',
          'hasTags',
          'hasAnyTag',
        ].includes(op),
    ) ||
    conditions.filter(({ field }) => field === 'category').length >= 2 ||
    conditions.filter(({ field }) => field === 'category_group').length >= 1;

  const setSelectedCategories = (newCategories: CategoryEntity[]) => {
    const newCategoryIdSet = new Set(newCategories.map(({ id }) => id));
    const allCategoryIds = categories.list.map(({ id }) => id);
    const allCategoriesSelected = !allCategoryIds.find(
      id => !newCategoryIdSet.has(id),
    );
    const newCondition = {
      field: 'category',
      op: 'oneOf',
      value: newCategories.map(({ id }) => id),
      type: 'id',
    } satisfies RuleConditionEntity;

    const existingCategoryCondition = conditions.find(
      ({ field }) => field === 'category',
    );

    // If the existing conditions already have one for "category" - replace it
    if (existingCategoryCondition) {
      // If we selected all categories - remove the filter (default state)
      if (allCategoriesSelected) {
        onDeleteFilter(existingCategoryCondition);
        return;
      }

      // Update the "notOneOf" condition if it's already set
      if (existingCategoryCondition.op === 'notOneOf') {
        onUpdateFilter(existingCategoryCondition, {
          ...existingCategoryCondition,
          value: allCategoryIds.filter(id => !newCategoryIdSet.has(id)),
        });
        return;
      }

      // Otherwise use `oneOf` condition
      onUpdateFilter(existingCategoryCondition, newCondition);
      return;
    }

    // Don't add a new filter if all categories are selected (default state)
    if (allCategoriesSelected) {
      return;
    }

    // If the existing conditions does not have a "category" - append a new one
    onApplyFilter(newCondition);
  };

  const selectedCategories = useSelectedCategories(conditions, categories.list);
  const [startDate, setStartDate] = useState(loadReport.startDate);
  const [endDate, setEndDate] = useState(loadReport.endDate);
  const [mode, setMode] = useState(loadReport.mode);
  const [isDateStatic, setIsDateStatic] = useState(loadReport.isDateStatic);
  const [groupBy, setGroupBy] = useState(loadReport.groupBy);
  const [interval, setInterval] = useState(loadReport.interval);
  const [balanceType, setBalanceType] = useState(loadReport.balanceType);
  const [sortBy, setSortBy] = useState(loadReport.sortBy);

  const [showEmpty, setShowEmpty] = useState(loadReport.showEmpty);
  const [showOffBudget, setShowOffBudget] = useState(loadReport.showOffBudget);
  const [includeCurrentInterval, setIncludeCurrentInterval] = useState(
    loadReport.includeCurrentInterval,
  );
  const [showHiddenCategories, setShowHiddenCategories] = useState(
    loadReport.showHiddenCategories,
  );
  const [showUncategorized, setShowUncategorized] = useState(
    loadReport.showUncategorized,
  );
  const [trimIntervals, setTrimIntervals] = useState(loadReport.trimIntervals);
  const [showTrendLines, setShowTrendLines] = useState(
    loadReport.showTrendLines,
  );
  const [graphType, setGraphType] = useState(loadReport.graphType);

  const [dateRange, setDateRange] = useState(loadReport.dateRange);
  const dateRangeLine =
    interval === 'Daily'
      ? 0
      : ReportOptions.dateRange.filter(f => f[interval as keyof dateRangeProps])
          .length - 3;

  const [intervals, setIntervals] = useState(
    monthUtils.rangeInclusive(startDate, endDate),
  );
  const [earliestTransactionDate, setEarliestTransactionDate] =
    useState<TransactionEntity['date']>('');
  const [latestTransactionDate, setLatestTransactionDate] =
    useState<TransactionEntity['date']>('');
  const [report, setReport] = useState(loadReport);
  const [savedStatus, setSavedStatus] = useState<SavedStatus>(
    'savedStatus' in session
      ? (session.savedStatus as SavedStatus)
      : initialReport
        ? 'saved'
        : 'new',
  );

  const onApplyFilterConditions = useEffectEvent(
    (
      currentConditions?: RuleConditionEntity[],
      currentConditionsOp?: RuleConditionEntity['conditionsOp'],
    ) => {
      onApplyFilter(null);

      const filtersToApply =
        savedStatus !== 'saved' ? conditions : currentConditions;
      const conditionsOpToApply =
        savedStatus !== 'saved' ? conditionsOp : currentConditionsOp;

      filtersToApply?.forEach(onApplyFilter);
      if (conditionsOpToApply) {
        onConditionsOpChange(conditionsOpToApply);
      }
    },
  );

  const onSetAllIntervals = useEffectEvent(
    async (
      earliestTransaction: TransactionEntity,
      latestTransaction: TransactionEntity,
      interval: CustomReportEntity['interval'],
    ) => {
      const fromDate =
        interval === 'Weekly'
          ? 'dayFromDate'
          : (((ReportOptions.intervalMap.get(interval) || 'Day').toLowerCase() +
              'FromDate') as 'dayFromDate' | 'monthFromDate' | 'yearFromDate');

      const earliestInterval =
        interval === 'Weekly'
          ? monthUtils.weekFromDate(
              d.parseISO(
                fromDateRepr(
                  earliestTransaction.date || monthUtils.currentDay(),
                ),
              ),
              firstDayOfWeekIdx,
            )
          : monthUtils[fromDate](
              d.parseISO(
                fromDateRepr(
                  earliestTransaction.date || monthUtils.currentDay(),
                ),
              ),
            );

      const latestInterval =
        interval === 'Weekly'
          ? monthUtils.weekFromDate(
              d.parseISO(
                fromDateRepr(latestTransaction.date || monthUtils.currentDay()),
              ),
              firstDayOfWeekIdx,
            )
          : monthUtils[fromDate](
              d.parseISO(
                fromDateRepr(latestTransaction.date || monthUtils.currentDay()),
              ),
            );

      const currentInterval =
        interval === 'Weekly'
          ? monthUtils.currentWeek(firstDayOfWeekIdx)
          : interval === 'Daily'
            ? monthUtils.currentDay()
            : interval === 'Yearly'
              ? monthUtils.currentYear()
              : monthUtils.currentMonth();

      const maxInterval =
        latestInterval > currentInterval ? latestInterval : currentInterval;

      const allIntervals =
        interval === 'Weekly'
          ? monthUtils.weekRangeInclusive(
              earliestInterval,
              maxInterval,
              firstDayOfWeekIdx,
            )
          : monthUtils[
              ReportOptions.intervalRange.get(interval) || 'rangeInclusive'
            ](earliestInterval, maxInterval);

      const allIntervalsMap = allIntervals
        .map((inter: string) => ({
          name: inter,
          pretty: monthUtils.format(
            inter,
            ReportOptions.intervalFormat.get(interval) || '',
            locale,
          ),
        }))
        .reverse();

      setAllIntervals(allIntervalsMap);
    },
  );

  const onSetStartAndEndDates = useEffectEvent(
    (
      earliestTransaction: TransactionEntity,
      latestTransaction: TransactionEntity,
      dateRange: CustomReportEntity['dateRange'],
      isDateStatic: CustomReportEntity['isDateStatic'],
      includeCurrentInterval: CustomReportEntity['includeCurrentInterval'],
    ) => {
      if (!isDateStatic) {
        const [dateStart, dateEnd] = getLiveRange(
          dateRange,
          earliestTransaction
            ? earliestTransaction.date
            : monthUtils.currentDay(),
          latestTransaction ? latestTransaction.date : monthUtils.currentDay(),
          includeCurrentInterval,
          firstDayOfWeekIdx,
        );
        setStartDate(dateStart);
        setEndDate(dateEnd);
      }
    },
  );

  useEffect(() => {
    async function run() {
      onApplyFilterConditions(report.conditions, report.conditionsOp);

      const earliestTransaction = await send('get-earliest-transaction');
      setEarliestTransactionDate(
        earliestTransaction
          ? earliestTransaction.date
          : monthUtils.currentDay(),
      );

      const latestTransaction = await send('get-latest-transaction');
      setLatestTransactionDate(
        latestTransaction ? latestTransaction.date : monthUtils.currentDay(),
      );

      void onSetAllIntervals(earliestTransaction, latestTransaction, interval);
      onSetStartAndEndDates(
        earliestTransaction,
        latestTransaction,
        dateRange,
        isDateStatic,
        includeCurrentInterval,
      );
    }

    void run();
  }, [
    interval,
    dateRange,
    firstDayOfWeekIdx,
    isDateStatic,
    report.conditions,
    report.conditionsOp,
    includeCurrentInterval,
    savedStatus,
  ]);

  useEffect(() => {
    const [start, end] = [startDate, endDate];
    if (interval === 'Weekly') {
      setIntervals(
        monthUtils.weekRangeInclusive(start, end, firstDayOfWeekIdx),
      );
    } else {
      setIntervals(
        monthUtils[
          ReportOptions.intervalRange.get(interval) || 'rangeInclusive'
        ](start, end),
      );
    }
  }, [interval, startDate, endDate, firstDayOfWeekIdx]);

  const balanceTypeOp: balanceTypeOpType =
    ReportOptions.balanceTypeMap.get(balanceType) || 'totalDebts';
  const sortByOp: sortByOpType = sortBy || 'desc';
  const { data: payees = [] } = usePayees();
  const { data: accounts = [] } = useAccounts();

  const hasWarning = calculateHasWarning(conditions, {
    categories: categories.list,
    payees,
    accounts,
  });

  useEffect(() => {
    if (balanceTypeOp !== 'totalBudgeted') {
      return;
    }

    const supportedConditions = conditions.filter(cond =>
      BUDGETED_SUPPORTED_CONDITION_FIELDS.has(cond.field),
    );

    if (supportedConditions.length === conditions.length) {
      return;
    }

    setSessionReport('conditions', supportedConditions);
    onApplyFilter(null);
    supportedConditions.forEach(condition => {
      onApplyFilter(condition);
    });
  }, [balanceTypeOp, conditions, onApplyFilter]);

  const getGroupData = useMemo(() => {
    return createGroupedSpreadsheet({
      startDate,
      endDate,
      interval,
      categories,
      budgetType,
      conditions,
      conditionsOp,
      showEmpty,
      showOffBudget,
      showHiddenCategories,
      showUncategorized,
      trimIntervals,
      balanceTypeOp,
      sortByOp,
      firstDayOfWeekIdx,
    });
  }, [
    startDate,
    endDate,
    interval,
    budgetType,
    balanceTypeOp,
    categories,
    conditions,
    conditionsOp,
    showEmpty,
    showOffBudget,
    showHiddenCategories,
    showUncategorized,
    trimIntervals,
    sortByOp,
    firstDayOfWeekIdx,
  ]);

  const getGraphData = useMemo(() => {
    return createCustomSpreadsheet({
      startDate,
      endDate,
      interval,
      categories,
      budgetType,
      conditions,
      conditionsOp,
      showEmpty,
      showOffBudget,
      showHiddenCategories,
      showUncategorized,
      trimIntervals,
      groupBy,
      balanceTypeOp,
      sortByOp,
      payees,
      accounts,
      graphType,
      firstDayOfWeekIdx,
    });
  }, [
    startDate,
    endDate,
    interval,
    groupBy,
    budgetType,
    balanceTypeOp,
    categories,
    payees,
    accounts,
    conditions,
    conditionsOp,
    showEmpty,
    showOffBudget,
    showHiddenCategories,
    showUncategorized,
    trimIntervals,
    sortByOp,
    graphType,
    firstDayOfWeekIdx,
  ]);
  const graphData = useReport('default', getGraphData);
  const groupedData = useReport('grouped', getGroupData);

  const data: DataEntity | null = graphData
    ? { ...graphData, groupedData }
    : null;

  const customReportItems: CustomReportEntity = {
    id: '',
    name: '',
    startDate,
    endDate,
    isDateStatic,
    dateRange,
    mode,
    groupBy,
    interval,
    balanceType,
    sortBy,
    showEmpty,
    showOffBudget,
    showHiddenCategories,
    includeCurrentInterval,
    showUncategorized,
    trimIntervals,
    showTrendLines,
    graphType,
    conditions,
    conditionsOp,
  };

  const navigate = useNavigate();
  const [, setScrollWidth] = useState(0);

  useEffect(() => {
    if (disabledLegendLabel(mode, graphType, 'disableLegend')) {
      setViewLegendPref(false);
    }

    if (disabledLegendLabel(mode, graphType, 'disableLabel')) {
      setViewLabelsPref(false);
    }
  }, [setViewLegendPref, setViewLabelsPref, mode, graphType]);

  if (allIntervals.length === 0) {
    return null;
  }

  const defaultModeItems = (graph: string, item: string) => {
    const chooseGraph = graph || graphType;
    const newGraph =
      ((disabledList.modeGraphsMap.get(item) || []).includes(chooseGraph)
        ? defaultsList.modeGraphsMap.get(item)
        : chooseGraph) ?? chooseGraph;
    if ((disabledList.modeGraphsMap.get(item) || []).includes(graphType)) {
      setSessionReport('graphType', newGraph);
      setGraphType(newGraph);
    }

    if (
      (disabledGraphList(item, newGraph, 'disabledSplit') || []).includes(
        groupBy,
      )
    ) {
      const cond = defaultsGraphList(item, newGraph, 'defaultSplit');
      setSessionReport('groupBy', cond);
      setGroupBy(cond);
    }

    if (
      (disabledGraphList(item, newGraph, 'disabledType') || []).includes(
        balanceType,
      )
    ) {
      const cond = defaultsGraphList(item, newGraph, 'defaultType');
      setSessionReport('balanceType', cond);
      setBalanceType(cond);
    }
  };

  const defaultItems = (item: string) => {
    const chooseGraph = ReportOptions.groupByItems.has(item) ? graphType : item;
    if (
      (disabledGraphList(mode, chooseGraph, 'disabledSplit') || []).includes(
        groupBy,
      )
    ) {
      const cond = defaultsGraphList(mode, chooseGraph, 'defaultSplit');
      setSessionReport('groupBy', cond);
      setGroupBy(cond);
    }
    if (
      (disabledGraphList(mode, chooseGraph, 'disabledType') || []).includes(
        balanceType,
      )
    ) {
      const cond = defaultsGraphList(mode, chooseGraph, 'defaultType');
      setSessionReport('balanceType', cond);
      setBalanceType(cond);
    }

    const defaultSort = defaultsGraphList(mode, chooseGraph, 'defaultSort');
    if (defaultSort) {
      setSessionReport('sortBy', defaultSort);
      setSortBy(defaultSort as CustomReportEntity['sortBy']);
    }
  };

  const isItemDisabled = (type: string) => {
    switch (type) {
      case 'ShowLegend': {
        return disabledLegendLabel(mode, graphType, 'disableLegend') || false;
      }
      case 'ShowLabels': {
        return disabledLegendLabel(mode, graphType, 'disableLabel') || false;
      }
      default:
        return (
          (disabledList.modeGraphsMap.get(mode) || []).includes(type) || false
        );
    }
  };

  const disabledItems = (type: string) => {
    switch (type) {
      case 'split':
        return disabledGraphList(mode, graphType, 'disabledSplit') || [];
      case 'type':
        return graphType === 'BarGraph' && groupBy === 'Interval'
          ? []
          : disabledGraphList(mode, graphType, 'disabledType') || [];
      default:
        return [];
    }
  };

  const onChangeDates = (dateStart: string, dateEnd: string) => {
    setSessionReport('startDate', dateStart);
    setSessionReport('endDate', dateEnd);
    setStartDate(dateStart);
    setEndDate(dateEnd);
    onReportChange({ type: 'modify' });
  };

  const onChangeViews = (viewType: string) => {
    if (viewType === 'viewLegend') {
      setViewLegendPref(!viewLegend);
    }
    if (viewType === 'viewSummary') {
      setViewSummaryPref(!viewSummary);
    }
    if (viewType === 'viewLabels') {
      setViewLabelsPref(!viewLabels);
    }
  };

  const setReportData = (input: CustomReportEntity) => {
    setStartDate(input.startDate);
    setEndDate(input.endDate);
    setIsDateStatic(input.isDateStatic);
    setDateRange(input.dateRange);
    setMode(input.mode);
    setGroupBy(input.groupBy);
    setInterval(input.interval);
    setBalanceType(input.balanceType);
    setSortBy(input.sortBy);
    setShowEmpty(input.showEmpty);
    setShowOffBudget(input.showOffBudget);
    setShowHiddenCategories(input.showHiddenCategories);
    setIncludeCurrentInterval(input.includeCurrentInterval);
    setShowUncategorized(input.showUncategorized);
    setTrimIntervals(input.trimIntervals);
    setShowTrendLines(input.showTrendLines);
    setGraphType(input.graphType);
    onApplyFilter(null);
    (input.conditions || []).forEach(condition => {
      onApplyFilter(condition);
    });
    onConditionsOpChange(input.conditionsOp);
  };

  const onReportChange = (
    params:
      | {
          type: 'add-update';
          savedReport: CustomReportEntity;
        }
      | {
          type: 'rename';
          savedReport?: CustomReportEntity;
        }
      | {
          type: 'modify';
        }
      | {
          type: 'reload';
        }
      | {
          type: 'reset';
        }
      | {
          type: 'choose';
          savedReport?: CustomReportEntity;
        },
  ) => {
    switch (params.type) {
      case 'add-update':
        sessionStorage.clear();
        setSessionReport('savedStatus', 'saved');
        setSavedStatus('saved');
        setReport(params.savedReport);

        if (params.savedReport.id !== initialReport?.id) {
          void navigate(`/reports/custom/${params.savedReport.id}`);
        }
        break;
      case 'rename':
        setReport({ ...report, name: params.savedReport?.name || '' });
        break;
      case 'modify':
        if (report.name) {
          setSessionReport('savedStatus', 'modified');
          setSavedStatus('modified');
        }
        break;
      case 'reload':
        sessionStorage.clear();
        setSessionReport('savedStatus', 'saved');
        setSavedStatus('saved');
        setReportData(initialReport ?? defaultReport);
        break;
      case 'reset':
        sessionStorage.clear();
        setSavedStatus('new');
        setReport(defaultReport);
        setReportData(defaultReport);
        break;
      case 'choose': {
        sessionStorage.clear();
        const newReport = params.savedReport || report;
        setSessionReport('savedStatus', 'saved');
        setSavedStatus('saved');
        setReport(newReport);
        setReportData(newReport);
        void navigate(`/reports/custom/${newReport.id}`);
        break;
      }
      default:
    }
  };

  const onBackClick = () => {
    void navigate('/reports');
  };

  return (
    <Page
      header={
        isNarrowWidth ? (
          <MobilePageHeader
            title={t('Custom Report: {{name}}', {
              name: report.name ?? t('Unsaved report'),
            })}
            leftContent={<MobileBackButton onPress={onBackClick} />}
          />
        ) : (
          <PageHeader
            title={
              <Trans>
                <Text>
                  <Trans>Custom Report:</Trans>
                </Text>{' '}
                <Text style={{ marginLeft: 5, color: theme.pageTextPositive }}>
                  {
                    {
                      name:
                        report.name?.length > 0
                          ? report.name
                          : t('Unsaved report'),
                    } as TransObjectLiteral
                  }
                </Text>
              </Trans>
            }
          />
        )
      }
      padding={0}
    >
      <View
        style={{
          flexDirection: 'row',
          paddingLeft: !isNarrowWidth ? 20 : undefined,
          flex: 1,
        }}
      >
        {!isNarrowWidth && (
          <ReportSidebar
            customReportItems={customReportItems}
            selectedCategories={selectedCategories}
            categories={categories}
            dateRangeLine={dateRangeLine}
            allIntervals={allIntervals}
            setDateRange={setDateRange}
            setGraphType={setGraphType}
            setGroupBy={setGroupBy}
            setInterval={setInterval}
            setBalanceType={setBalanceType}
            setSortBy={setSortBy}
            setMode={setMode}
            setIsDateStatic={setIsDateStatic}
            setShowEmpty={setShowEmpty}
            setShowOffBudget={setShowOffBudget}
            setShowHiddenCategories={setShowHiddenCategories}
            setIncludeCurrentInterval={setIncludeCurrentInterval}
            setShowUncategorized={setShowUncategorized}
            setTrimIntervals={setTrimIntervals}
            setShowTrendLines={setShowTrendLines}
            setSelectedCategories={setSelectedCategories}
            onChangeDates={onChangeDates}
            onReportChange={onReportChange}
            disabledItems={disabledItems}
            defaultItems={defaultItems}
            defaultModeItems={defaultModeItems}
            earliestTransaction={earliestTransactionDate}
            latestTransaction={latestTransactionDate}
            firstDayOfWeekIdx={firstDayOfWeekIdx}
            isComplexCategoryCondition={isComplexCategoryCondition}
          />
        )}
        <View
          style={{
            flex: 1,
          }}
        >
          {!isNarrowWidth && (
            <ReportTopbar
              customReportItems={customReportItems}
              report={report}
              savedStatus={savedStatus}
              setGraphType={setGraphType}
              viewLegend={viewLegend}
              viewSummary={viewSummary}
              viewLabels={viewLabels}
              onApplyFilter={onApplyFilter}
              onChangeViews={onChangeViews}
              onReportChange={onReportChange}
              isItemDisabled={isItemDisabled}
              defaultItems={defaultItems}
            />
          )}
          {conditions && conditions.length > 0 && (
            <View
              style={{
                marginBottom: 10,
                marginLeft: 5,
                marginRight: 5,
                gap: 10,
                flexShrink: 0,
              }}
            >
              <View
                style={{
                  flexShrink: 0,
                  flexDirection: 'row',
                  alignItems: 'flex-start',
                  justifyContent: 'flex-start',
                }}
              >
                <AppliedFilters
                  conditions={conditions}
                  onUpdate={(oldFilter, newFilter) => {
                    setSessionReport(
                      'conditions',
                      conditions.map(f => (f === oldFilter ? newFilter : f)),
                    );
                    onReportChange({ type: 'modify' });
                    onUpdateFilter(oldFilter, newFilter);
                  }}
                  onDelete={deletedFilter => {
                    setSessionReport(
                      'conditions',
                      conditions.filter(f => f !== deletedFilter),
                    );
                    onDeleteFilter(deletedFilter);
                    onReportChange({ type: 'modify' });
                  }}
                  conditionsOp={conditionsOp}
                  onConditionsOpChange={co => {
                    onConditionsOpChange(co);
                    onReportChange({ type: 'modify' });
                  }}
                />
              </View>

              {hasWarning && (
                <Warning style={{ paddingTop: 5, paddingBottom: 5 }}>
                  {t(
                    'This report is configured to use a non-existing filter value (i.e. category/account/payee).',
                  )}
                </Warning>
              )}
            </View>
          )}
          <View
            id="custom-report-content"
            style={{
              backgroundColor: theme.tableBackground,
              flexDirection: 'row',
              flex: '1 0 auto',
            }}
          >
            <View
              style={{
                flex: 1,
                padding: 10,
              }}
            >
              {graphType !== 'TableGraph' && data && (
                <View
                  style={{
                    alignItems: 'flex-end',
                    paddingTop: 10,
                  }}
                >
                  <View
                    style={{
                      ...styles.mediumText,
                      fontWeight: 500,
                      marginBottom: 5,
                    }}
                  >
                    <AlignedText
                      left={<Block>{balanceType}:</Block>}
                      right={
                        <FinancialText>
                          <PrivacyFilter>
                            {format(data[balanceTypeOp], 'financial')}
                          </PrivacyFilter>
                        </FinancialText>
                      }
                    />
                  </View>
                </View>
              )}
              <View style={{ flex: 1, overflow: 'auto' }}>
                {data ? (
                  <ChooseGraph
                    data={data}
                    filters={conditions}
                    mode={mode}
                    graphType={graphType}
                    balanceType={balanceType}
                    groupBy={groupBy}
                    interval={interval}
                    setScrollWidth={setScrollWidth}
                    viewLabels={viewLabels}
                    compact={false}
                    showHiddenCategories={showHiddenCategories}
                    showOffBudget={showOffBudget}
                    showTrendLines={showTrendLines}
                    intervalsCount={intervals.length}
                  />
                ) : (
                  <LoadingIndicator message={t('Loading report...')} />
                )}
              </View>
            </View>
            {(viewLegend || viewSummary) && data && !isNarrowWidth && (
              <View
                style={{
                  padding: 10,
                  minWidth: 300,
                  textAlign: 'center',
                }}
              >
                {viewSummary && (
                  <ReportSummary
                    startDate={startDate}
                    endDate={endDate}
                    balanceTypeOp={balanceTypeOp}
                    data={data}
                    interval={interval}
                    intervalsCount={intervals.length}
                  />
                )}
                {viewLegend && (
                  <ReportLegend
                    legend={data.legend}
                    groupBy={groupBy}
                    interval={interval}
                  />
                )}
              </View>
            )}
          </View>
        </View>
      </View>
    </Page>
  );
}
