import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';

import { Block } from '@actual-app/components/block';
import { useResponsive } from '@actual-app/components/hooks/useResponsive';
import { styles } from '@actual-app/components/styles';
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 {
  AccountEntity,
  CrossoverWidget,
} from '@actual-app/core/types/models';

import { PrivacyFilter } from '#components/PrivacyFilter';
import { CrossoverGraph } from '#components/reports/graphs/CrossoverGraph';
import { LoadingIndicator } from '#components/reports/LoadingIndicator';
import { ReportCard } from '#components/reports/ReportCard';
import { ReportCardName } from '#components/reports/ReportCardName';
import { calculateTimeRange } from '#components/reports/reportRanges';
import { defaultTimeFrame } from '#components/reports/reports/Crossover';
import { createCrossoverSpreadsheet } from '#components/reports/spreadsheets/crossover-spreadsheet';
import type { CrossoverData } from '#components/reports/spreadsheets/crossover-spreadsheet';
import { useReport } from '#components/reports/useReport';
import { useCategories } from '#hooks/useCategories';
import { useFormat } from '#hooks/useFormat';
import { useLocale } from '#hooks/useLocale';

type CrossoverCardProps = {
  widgetId: string;
  isEditing?: boolean;
  accounts: AccountEntity[];
  meta?: CrossoverWidget['meta'];
  onMetaChange: (newMeta: CrossoverWidget['meta']) => void;
};

export function CrossoverCard({
  widgetId,
  isEditing,
  accounts,
  meta = {},
  onMetaChange,
}: CrossoverCardProps) {
  const locale = useLocale();
  const { t } = useTranslation();
  const { data: categories = { grouped: [], list: [] } } = useCategories();
  const { isNarrowWidth } = useResponsive();

  const [nameMenuOpen, setNameMenuOpen] = useState(false);

  // Calculate date range from meta or use default range
  const [start, setStart] = useState<string>('');
  const [end, setEnd] = useState<string>('');

  const format = useFormat();

  useEffect(() => {
    let isMounted = true;
    async function calculateDateRange() {
      const currentMonth = monthUtils.currentMonth();
      const previousMonth = monthUtils.subMonths(currentMonth, 1);

      // Fetch earliest transaction to build the valid range
      const earliestTransactionData = await send('get-earliest-transaction');
      if (!isMounted) return;

      // Build allMonths list similar to Crossover.tsx
      const earliestDate = earliestTransactionData
        ? earliestTransactionData.date
        : monthUtils.firstDayOfMonth(previousMonth);
      const latestDate = monthUtils.lastDayOfMonth(previousMonth);

      const allMonths = monthUtils
        .rangeInclusive(earliestDate, latestDate)
        .map(month => ({
          name: month,
          pretty: monthUtils.format(month, 'MMMM yyyy', locale),
        }))
        .reverse();

      // Use calculateTimeRange to get initial values based on timeFrame mode
      const [initialStart, initialEnd, mode] = calculateTimeRange(
        meta?.timeFrame,
        defaultTimeFrame,
        previousMonth,
      );

      const earliestMonth = allMonths[allMonths.length - 1].name;
      const latestMonth = allMonths[0].name;
      let start = initialStart;
      let end = initialEnd;

      const clampMonth = (m: string) => {
        if (monthUtils.isBefore(m, earliestMonth)) return earliestMonth;
        if (monthUtils.isAfter(m, latestMonth)) return latestMonth;
        return m;
      };

      // Apply mode-specific logic similar to Crossover.tsx
      if (mode === 'sliding-window') {
        // Shift both start and end back one month for sliding-window
        start = clampMonth(monthUtils.subMonths(start, 1));
        end = clampMonth(monthUtils.subMonths(end, 1));
      } else if (mode === 'full') {
        start = earliestMonth;
        end = latestMonth;
      } else {
        // static mode
        start = clampMonth(start);
        end = clampMonth(end);
      }

      // Ensure end doesn't go before start
      if (monthUtils.isBefore(end, start)) {
        end = start;
      }

      if (isMounted) {
        setStart(start);
        setEnd(end);
      }
    }
    void calculateDateRange();
    return () => {
      isMounted = false;
    };
  }, [meta?.timeFrame, locale]);

  const [isCardHovered, setIsCardHovered] = useState(false);
  const onCardHover = useCallback(() => setIsCardHovered(true), []);
  const onCardHoverEnd = useCallback(() => setIsCardHovered(false), []);

  const showHiddenCategories = meta?.showHiddenCategories ?? false;

  // Memoize these to prevent unnecessary re-renders
  const expenseCategoryIds = useMemo(() => {
    const storedIds = meta?.expenseCategoryIds;
    const base =
      storedIds !== undefined
        ? categories.list.filter(c => storedIds.includes(c.id))
        : categories.list.filter(c => !c.is_income);
    return base.filter(c => showHiddenCategories || !c.hidden).map(c => c.id);
  }, [meta?.expenseCategoryIds, categories.list, showHiddenCategories]);

  const incomeAccountIds = useMemo(
    () => meta?.incomeAccountIds ?? accounts.map(a => a.id),
    [meta?.incomeAccountIds, accounts],
  );

  const swr = meta?.safeWithdrawalRate ?? 0.04;
  const estimatedReturn = meta?.estimatedReturn ?? null;
  const expectedContribution = meta?.expectedContribution ?? null;
  const projectionType: 'hampel' | 'median' | 'mean' =
    meta?.projectionType ?? 'hampel';
  const expenseAdjustmentFactor = meta?.expenseAdjustmentFactor ?? 1.0;

  const params = useMemo(
    () =>
      createCrossoverSpreadsheet({
        start,
        end,
        expenseCategoryIds,
        incomeAccountIds,
        safeWithdrawalRate: swr,
        estimatedReturn,
        expectedContribution,
        projectionType,
        expenseAdjustmentFactor,
      }),
    [
      start,
      end,
      expenseCategoryIds,
      incomeAccountIds,
      swr,
      estimatedReturn,
      expectedContribution,
      projectionType,
      expenseAdjustmentFactor,
    ],
  );

  const data = useReport<CrossoverData>('crossover', params);

  // Get years to retire from spreadsheet data
  const yearsToRetire = data?.yearsToRetire ?? null;

  return (
    <ReportCard
      widgetId={widgetId}
      isEditing={isEditing}
      disableClick={nameMenuOpen}
      to={`/reports/crossover/${widgetId}`}
      onRename={() => setNameMenuOpen(true)}
    >
      <View
        style={{ flex: 1 }}
        onPointerEnter={onCardHover}
        onPointerLeave={onCardHoverEnd}
      >
        <View style={{ flexDirection: 'row', padding: 20 }}>
          <View style={{ flex: 1 }}>
            <ReportCardName
              name={meta?.name || t('Crossover Point')}
              isEditing={nameMenuOpen}
              onChange={newName => {
                onMetaChange({
                  ...meta,
                  name: newName,
                });
                setNameMenuOpen(false);
              }}
              onClose={() => setNameMenuOpen(false)}
            />
            {/* Date range is now fixed and not configurable */}
          </View>
          {data && (
            <View style={{ textAlign: 'right', whiteSpace: 'nowrap' }}>
              <Block
                style={{
                  ...styles.mediumText,
                  fontWeight: 500,
                  marginBottom: 5,
                }}
              >
                <PrivacyFilter activationFilters={[!isCardHovered]}>
                  {yearsToRetire != null
                    ? t('{{years}} years', {
                        years: format(yearsToRetire, 'number'),
                      })
                    : t('N/A')}
                </PrivacyFilter>
              </Block>
              <Block
                style={{
                  fontSize: 12,
                  color: theme.pageTextSubdued,
                }}
              >
                <Trans>Years to Retire</Trans>
              </Block>
            </View>
          )}
        </View>

        {data ? (
          <CrossoverGraph
            graphData={data.graphData}
            compact
            showTooltip={!isEditing && !isNarrowWidth}
            style={{ height: 'auto', flex: 1 }}
          />
        ) : (
          <LoadingIndicator />
        )}
      </View>
    </ReportCard>
  );
}
