File size: 3,653 Bytes
c09f67c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import { format, parse, parseISO } from "date-fns";

/**
 * Maps chart type identifiers to natural language names
 */
const chartTypeMap: Record<string, string> = {
  "monthly-revenue": "revenue",
  revenue: "revenue",
  profit: "profit",
  "burn-rate": "burn rate",
  expenses: "expenses",
  "revenue-forecast": "revenue forecast",
  runway: "runway",
  "category-expenses": "category expenses",
  "stacked-bar": "expenses",
  "revenue-trend": "revenue trends",
  "cash-flow": "cash flow",
  "growth-rate": "growth rate",
  "business-health-score": "business health score",
  "invoice-payment": "invoice payments",
  "tax-trend": "tax trends",
  "stress-test": "cash flow stress test",
};

/**
 * Gets a natural language name for a chart type
 */
export function getChartTypeName(chartId: string): string {
  return chartTypeMap[chartId] || chartId;
}

/**
 * Parses a date string (could be ISO string, month name, etc.) and returns a Date object
 */
function parseDate(dateStr: string): Date | null {
  // Try ISO string first (use parseISO for correct timezone handling)
  if (dateStr.includes("T") || dateStr.includes("-")) {
    const parsed = parseISO(dateStr);
    if (!Number.isNaN(parsed.getTime())) {
      return parsed;
    }
  }

  // Try month abbreviations (Jan, Feb, etc.)
  const monthMap: Record<string, number> = {
    Jan: 0,
    Feb: 1,
    Mar: 2,
    Apr: 3,
    May: 4,
    Jun: 5,
    Jul: 6,
    Aug: 7,
    Sep: 8,
    Oct: 9,
    Nov: 10,
    Dec: 11,
  };

  if (monthMap[dateStr] !== undefined) {
    // Use current year for month-only dates
    const now = new Date();
    return new Date(now.getFullYear(), monthMap[dateStr], 1);
  }

  // Try parsing with date-fns common formats
  const formats = ["MMM", "MMMM", "yyyy-MM-dd", "MM/dd/yyyy"];
  for (const fmt of formats) {
    try {
      const parsed = parse(dateStr, fmt, new Date());
      if (!Number.isNaN(parsed.getTime())) {
        return parsed;
      }
    } catch {
      // Continue to next format
    }
  }

  return null;
}

/**
 * Formats a date range for natural language display
 */
function formatDateRange(startDate: Date, endDate: Date): string {
  const now = new Date();
  const currentYear = now.getFullYear();

  // Check if both dates are in the same year
  const startYear = startDate.getFullYear();
  const endYear = endDate.getFullYear();

  // If dates are months only (day is 1), format as month names
  if (
    startDate.getDate() === 1 &&
    endDate.getDate() === 1 &&
    startYear === endYear &&
    startYear === currentYear
  ) {
    const startMonth = format(startDate, "MMMM");
    const endMonth = format(endDate, "MMMM");

    if (startMonth === endMonth) {
      return startMonth;
    }

    return `${startMonth} to ${endMonth}`;
  }

  // Format as full dates if different years or specific dates
  const startFormatted = format(startDate, "MMMM d");
  const endFormatted = format(endDate, "MMMM d");

  if (startFormatted === endFormatted) {
    return startFormatted;
  }

  return `${startFormatted} to ${endFormatted}`;
}

/**
 * Generates a natural language message for chart period selection
 */
export function generateChartSelectionMessage(
  startDate: string,
  endDate: string,
  chartType: string,
): string {
  const chartName = getChartTypeName(chartType);

  const start = parseDate(startDate);
  const end = parseDate(endDate);

  if (!start || !end) {
    // Fallback to simple format if parsing fails
    return `Show me a breakdown of ${chartName} from ${startDate} to ${endDate}`;
  }

  const dateRange = formatDateRange(start, end);
  return `Show me a breakdown of ${chartName} from ${dateRange}`;
}