import type { CompanyFinancialStatementsResponse, DimensionBreakdownRow, FilingFaithfulStatementRow, FinancialHistoryWindow, FinancialStatementKind, FinancialStatementMode, FinancialStatementPeriod, StandardizedStatementRow } from '@/lib/types'; import { listFilingsRecords } from '@/lib/server/repos/filings'; import { countFilingStatementSnapshotStatuses, type DimensionStatementSnapshotRow, type FilingFaithfulStatementSnapshotRow, type FilingStatementSnapshotRecord, listFilingStatementSnapshotsByTicker, type StandardizedStatementSnapshotRow } from '@/lib/server/repos/filing-statements'; type GetCompanyFinancialStatementsInput = { ticker: string; mode: FinancialStatementMode; statement: FinancialStatementKind; window: FinancialHistoryWindow; includeDimensions: boolean; cursor?: string | null; limit?: number; v2Enabled: boolean; queuedSync: boolean; }; type FinancialStatementRowByMode = StandardizedStatementRow | FilingFaithfulStatementRow; function safeTicker(input: string) { return input.trim().toUpperCase(); } function isFinancialForm(type: string): type is '10-K' | '10-Q' { return type === '10-K' || type === '10-Q'; } function rowDimensionMatcher(row: { key: string; concept: string | null }, item: DimensionStatementSnapshotRow) { const concept = row.concept?.toLowerCase() ?? ''; const itemConcept = item.concept?.toLowerCase() ?? ''; if (item.rowKey === row.key) { return true; } return Boolean(concept && itemConcept && concept === itemConcept); } function periodSorter(left: FinancialStatementPeriod, right: FinancialStatementPeriod) { const byDate = Date.parse(left.filingDate) - Date.parse(right.filingDate); if (Number.isFinite(byDate) && byDate !== 0) { return byDate; } return left.id.localeCompare(right.id); } function resolveDimensionPeriodId(rawPeriodId: string, periods: FinancialStatementPeriod[]) { const exact = periods.find((period) => period.id === rawPeriodId); if (exact) { return exact.id; } const byDate = periods.find((period) => period.filingDate === rawPeriodId || period.periodEnd === rawPeriodId); return byDate?.id ?? null; } function getRowsForSnapshot( snapshot: FilingStatementSnapshotRecord, mode: FinancialStatementMode, statement: FinancialStatementKind ) { if (mode === 'standardized') { return snapshot.standardized_bundle?.statements?.[statement] ?? []; } return snapshot.statement_bundle?.statements?.[statement] ?? []; } function buildPeriods( snapshots: FilingStatementSnapshotRecord[], mode: FinancialStatementMode, statement: FinancialStatementKind ) { const map = new Map(); for (const snapshot of snapshots) { const rows = getRowsForSnapshot(snapshot, mode, statement); if (rows.length === 0) { continue; } const sourcePeriods = mode === 'standardized' ? snapshot.standardized_bundle?.periods : snapshot.statement_bundle?.periods; for (const period of sourcePeriods ?? []) { if (!map.has(period.id)) { map.set(period.id, { id: period.id, filingId: period.filingId, accessionNumber: period.accessionNumber, filingDate: period.filingDate, periodEnd: period.periodEnd, filingType: period.filingType, periodLabel: period.periodLabel }); } } } return [...map.values()].sort(periodSorter); } function buildRows( snapshots: FilingStatementSnapshotRecord[], periods: FinancialStatementPeriod[], mode: FinancialStatementMode, statement: FinancialStatementKind, includeDimensions: boolean ) { const rowMap = new Map(); const dimensionMap = includeDimensions ? new Map() : null; for (const snapshot of snapshots) { const rows = getRowsForSnapshot(snapshot, mode, statement); const dimensions = snapshot.dimension_bundle?.statements?.[statement] ?? []; if (mode === 'standardized') { for (const sourceRow of rows as StandardizedStatementSnapshotRow[]) { const existing = rowMap.get(sourceRow.key) as StandardizedStatementRow | undefined; const hasDimensions = dimensions.some((item) => rowDimensionMatcher(sourceRow, item)); if (!existing) { rowMap.set(sourceRow.key, { key: sourceRow.key, label: sourceRow.label, concept: sourceRow.concept, category: sourceRow.category, sourceConcepts: [...sourceRow.sourceConcepts], values: { ...sourceRow.values }, hasDimensions }); continue; } existing.hasDimensions = existing.hasDimensions || hasDimensions; for (const concept of sourceRow.sourceConcepts) { if (!existing.sourceConcepts.includes(concept)) { existing.sourceConcepts.push(concept); } } for (const [periodId, value] of Object.entries(sourceRow.values)) { if (!(periodId in existing.values)) { existing.values[periodId] = value; } } } } else { for (const sourceRow of rows as FilingFaithfulStatementSnapshotRow[]) { const rowKey = sourceRow.concept ? `concept-${sourceRow.concept.toLowerCase()}` : `label-${sourceRow.key}`; const existing = rowMap.get(rowKey) as FilingFaithfulStatementRow | undefined; const hasDimensions = dimensions.some((item) => rowDimensionMatcher(sourceRow, item)); if (!existing) { rowMap.set(rowKey, { key: rowKey, label: sourceRow.label, concept: sourceRow.concept, order: sourceRow.order, depth: sourceRow.depth, isSubtotal: sourceRow.isSubtotal, values: { ...sourceRow.values }, hasDimensions }); continue; } existing.hasDimensions = existing.hasDimensions || hasDimensions; existing.order = Math.min(existing.order, sourceRow.order); existing.depth = Math.min(existing.depth, sourceRow.depth); existing.isSubtotal = existing.isSubtotal || sourceRow.isSubtotal; for (const [periodId, value] of Object.entries(sourceRow.values)) { if (!(periodId in existing.values)) { existing.values[periodId] = value; } } } } if (dimensionMap) { for (const item of dimensions) { const periodId = resolveDimensionPeriodId(item.periodId, periods); if (!periodId) { continue; } const entry: DimensionBreakdownRow = { rowKey: item.rowKey, concept: item.concept, periodId, axis: item.axis, member: item.member, value: item.value, unit: item.unit }; const group = dimensionMap.get(item.rowKey); if (group) { group.push(entry); } else { dimensionMap.set(item.rowKey, [entry]); } } } } const rows = [...rowMap.values()].sort((a, b) => { const left = mode === 'standardized' ? a.label : `${(a as FilingFaithfulStatementRow).order.toString().padStart(5, '0')}::${a.label}`; const right = mode === 'standardized' ? b.label : `${(b as FilingFaithfulStatementRow).order.toString().padStart(5, '0')}::${b.label}`; return left.localeCompare(right); }); if (mode === 'standardized') { const standardized = rows as StandardizedStatementRow[]; const core = standardized.filter((row) => row.category === 'core'); const nonCore = standardized.filter((row) => row.category !== 'core'); const orderedRows = [...core, ...nonCore]; return { rows: orderedRows, dimensions: dimensionMap ? Object.fromEntries(dimensionMap.entries()) : null }; } return { rows: rows as FilingFaithfulStatementRow[], dimensions: dimensionMap ? Object.fromEntries(dimensionMap.entries()) : null }; } export function defaultFinancialSyncLimit(window: FinancialHistoryWindow) { return window === 'all' ? 120 : 60; } export async function getCompanyFinancialStatements(input: GetCompanyFinancialStatementsInput): Promise { const ticker = safeTicker(input.ticker); const snapshotResult = await listFilingStatementSnapshotsByTicker({ ticker, window: input.window, limit: input.limit, cursor: input.cursor }); const statuses = await countFilingStatementSnapshotStatuses(ticker); const filings = await listFilingsRecords({ ticker, limit: input.window === 'all' ? 250 : 120 }); const financialFilings = filings.filter((filing) => isFinancialForm(filing.filing_type)); const periods = buildPeriods(snapshotResult.snapshots, input.mode, input.statement); const rowResult = buildRows( snapshotResult.snapshots, periods, input.mode, input.statement, input.includeDimensions ); const latestFiling = filings[0] ?? null; return { company: { ticker, companyName: latestFiling?.company_name ?? ticker, cik: latestFiling?.cik ?? null }, mode: input.mode, statement: input.statement, window: input.window, periods, rows: rowResult.rows, nextCursor: snapshotResult.nextCursor, coverage: { filings: periods.length, rows: rowResult.rows.length, dimensions: rowResult.dimensions ? Object.values(rowResult.dimensions).reduce((total, rows) => total + rows.length, 0) : 0 }, dataSourceStatus: { enabled: input.v2Enabled, hydratedFilings: statuses.ready, partialFilings: statuses.partial, failedFilings: statuses.failed, pendingFilings: Math.max(0, financialFilings.length - statuses.ready - statuses.partial - statuses.failed), queuedSync: input.queuedSync }, dimensionBreakdown: rowResult.dimensions }; } export const __financialStatementsInternals = { buildPeriods, buildRows, defaultFinancialSyncLimit };