import type { OFXAccount, OFXTransaction } from "./types" export function parseOFX(content: string): OFXAccount | null { try { // Remove SGML header and clean up const xmlStart = content.indexOf("") if (xmlStart === -1) return null let xml = content.substring(xmlStart) // Convert SGML to XML-like format xml = xml.replace(/<(\w+)>([^<]+)(?=<)/g, "<$1>$2") // Extract account info const bankId = extractValue(xml, "BANKID") || extractValue(xml, "ORG") || "UNKNOWN" const accountId = extractValue(xml, "ACCTID") || "UNKNOWN" const accountType = extractValue(xml, "ACCTTYPE") || "CHECKING" const balanceStr = extractValue(xml, "BALAMT") || "0" const balance = Number.parseFloat(balanceStr) const balanceDate = extractValue(xml, "DTASOF") || new Date().toISOString() const currency = extractValue(xml, "CURDEF") || "EUR" // Extract transactions const transactions: OFXTransaction[] = [] const stmtTrnRegex = /([\s\S]*?)<\/STMTTRN>/gi let match while ((match = stmtTrnRegex.exec(xml)) !== null) { const trnXml = match[1] const fitId = extractValue(trnXml, "FITID") || `${Date.now()}-${Math.random()}` const dateStr = extractValue(trnXml, "DTPOSTED") || "" const amountStr = extractValue(trnXml, "TRNAMT") || "0" const name = extractValue(trnXml, "NAME") || extractValue(trnXml, "MEMO") || "Unknown" const memo = extractValue(trnXml, "MEMO") const checkNum = extractValue(trnXml, "CHECKNUM") const type = extractValue(trnXml, "TRNTYPE") || "OTHER" transactions.push({ fitId, date: parseOFXDate(dateStr), amount: Number.parseFloat(amountStr), name: cleanString(name), memo: memo ? cleanString(memo) : undefined, checkNum: checkNum ?? undefined, type, }) } return { bankId, accountId, accountType: mapAccountType(accountType), balance, balanceDate: parseOFXDate(balanceDate), currency, transactions, } } catch (error) { console.error("Error parsing OFX:", error) return null } } function extractValue(xml: string, tag: string): string | null { const regex = new RegExp(`<${tag}>([^<]+)`, "i") const match = xml.match(regex) return match ? match[1].trim() : null } function parseOFXDate(dateStr: string): string { if (!dateStr || dateStr.length < 8) return new Date().toISOString() const year = dateStr.substring(0, 4) const month = dateStr.substring(4, 6) const day = dateStr.substring(6, 8) return `${year}-${month}-${day}` } function mapAccountType(type: string): "CHECKING" | "SAVINGS" | "CREDIT_CARD" | "OTHER" { const upper = type.toUpperCase() if (upper.includes("CHECK") || upper.includes("CURRENT")) return "CHECKING" if (upper.includes("SAV")) return "SAVINGS" if (upper.includes("CREDIT")) return "CREDIT_CARD" return "OTHER" } function cleanString(str: string): string { return str.replace(/\s+/g, " ").trim() }