import { ISpreadsheetService } from "../interfaces/ISpreadsheetService"; export class MockSpreadsheetService implements ISpreadsheetService { // Store data as a map of sheetName -> array of rows (arrays of values) // Row 0 is headers. private sheets: Map = new Map(); constructor(initialData?: { [sheetName: string]: any[][] }) { if (initialData) { for (const [name, rows] of Object.entries(initialData)) { this.sheets.set(name, JSON.parse(JSON.stringify(rows))); // Deep copy } } } setSheetData(sheetName: string, data: any[][]) { this.sheets.set(sheetName, data); } private getSheet(sheetName: string): any[][] { if (!this.sheets.has(sheetName)) { // Create empty sheet with no headers if accessed but not defined? // Or throw error to mimic GAS? // Let's return empty array or throw. throw new Error(`Sheet '${sheetName}' not found in mock`); } return this.sheets.get(sheetName)!; } getHeaders(sheetName: string): string[] { const data = this.getSheet(sheetName); if (data.length === 0) return []; return data[0] as string[]; } getRowData(sheetName: string, row: number): any[] { const data = this.getSheet(sheetName); // Row is 1-based index if (row > data.length || row < 1) { throw new Error(`Row ${row} out of bounds`); } return data[row - 1]; // Convert to 0-based } getRowNumberByColumnValue(sheetName: string, columnName: string, value: any): number | undefined { const data = this.getSheet(sheetName); if (data.length < 2) return undefined; // Only headers or empty const headers = data[0]; const colIndex = headers.indexOf(columnName); if (colIndex === -1) return undefined; for (let i = 1; i < data.length; i++) { if (data[i][colIndex] === value) { return i + 1; // Convert 0-based index to 1-based row number } } return undefined; } setCellValueByColumnName(sheetName: string, row: number, columnName: string, value: any): void { const data = this.getSheet(sheetName); const headers = data[0]; const colIndex = headers.indexOf(columnName); if (colIndex === -1) { throw new Error(`Column '${columnName}' not found`); } // Ensure row exists, extend if necessary (basic behavior) while (data.length < row) { data.push(new Array(headers.length).fill("")); } data[row - 1][colIndex] = value; } getCellValueByColumnName(sheetName: string, row: number, columnName: string): any { const data = this.getSheet(sheetName); const headers = data[0]; const colIndex = headers.indexOf(columnName); if (colIndex === -1) return null; if (colIndex === -1) return null; if (row > data.length || row < 1) return null; return data[row - 1][colIndex]; } // Helper to store links: key = "sheetName:row:colIndex", value = url private links: Map = new Map(); getCellHyperlink(sheetName: string, row: number, columnName: string): string | null { const data = this.getSheet(sheetName); const colIndex = data[0].indexOf(columnName); if (colIndex === -1) return null; const key = `${sheetName}:${row}:${colIndex}`; return this.links.get(key) || null; } setCellHyperlink(sheetName: string, row: number, columnName: string, displayText: string, url: string): void { // Set text value this.setCellValueByColumnName(sheetName, row, columnName, displayText); // Set link const data = this.getSheet(sheetName); const colIndex = data[0].indexOf(columnName); if (colIndex !== -1) { const key = `${sheetName}:${row}:${colIndex}`; this.links.set(key, url); } } }