import { supabase } from '../lib/supabase'; import { AstroData, Profile } from '../types'; import { parseSAVTable, normalizeVargaType } from './asciiParser'; /** * importService handles transitions from raw Markdown files (from JHora/docs) * into structured Supabase table rows. */ export interface ParsedAstroData { profile: Omit & { id?: string }; vargaCharts: { type: string, text: string }[]; tableData: { type: string, content: string }[]; vargaAshtakavarga: Record>; } export async function parseAstroMarkdown(text: string): Promise { const lines = text.split('\n'); const data: ParsedAstroData = { profile: { name: 'Unknown', dob: '', birth_time: '', is_estimate: false }, vargaCharts: [], tableData: [], vargaAshtakavarga: {} }; let currentSection = ''; let currentBuffer: string[] = []; const flushBuffer = () => { if (!currentSection || currentBuffer.length === 0) return; const content = currentBuffer.join('\n').trim(); if (currentSection.startsWith('SAV_')) { const vType = currentSection.replace('SAV_', ''); data.vargaAshtakavarga[vType] = parseSAVTable(content); } else if (currentSection.startsWith('D') || currentSection === 'Rasi') { data.vargaCharts.push({ type: currentSection === 'Rasi' ? 'D1' : currentSection, text: content }); } else { data.tableData.push({ type: currentSection, content }); } currentBuffer = []; }; for (let i = 0; i < lines.length; i++) { const line = lines[i]; // Profile Info if (line.startsWith('**User**:')) data.profile.name = line.split(':')[1].trim(); if (line.startsWith('**DOB**:')) data.profile.dob = line.split(':')[1].trim(); if (line.startsWith('**Time**:')) { const timePart = line.split(':')[1].trim().split(' ')[0]; // Extract 21:23:07 data.profile.birth_time = timePart; data.profile.is_estimate = line.toLowerCase().includes('estimate: yes'); } // SAV Points Section (e.g. ### SAV - D9 or ### SAV - Navamsa) const savMatch = line.match(/^### SAV\s*-\s*(.*)/i); const vargaMatch = line.match(/^### (D\d+|Rasi|Navamsa|Navamsha|Dashamsha|Dasamsa)/i); const tableMatch = line.match(/^## .* (Longitude Table|Shadbala|Dasha|Additional Info)/i); if (savMatch || vargaMatch || tableMatch) { flushBuffer(); if (savMatch) { currentSection = `SAV_${normalizeVargaType(savMatch[1])}`; } else if (vargaMatch) { currentSection = normalizeVargaType(vargaMatch[1]); } else { currentSection = tableMatch ? tableMatch[1].toLowerCase().replace(' ', '_') : ''; } continue; } if (currentSection) { currentBuffer.push(line); } } flushBuffer(); return data; } export async function upsertProfileData(parsed: ParsedAstroData) { // 1. Upsert Profile const { data: profile, error: pError } = await supabase .from('profiles') .upsert({ name: parsed.profile.name, dob: parsed.profile.dob, birth_time: parsed.profile.birth_time, is_estimate: parsed.profile.is_estimate, varga_ashtakavarga: parsed.vargaAshtakavarga }, { onConflict: 'name' }) .select() .single(); if (pError || !profile) throw new Error(`Profile upsert failed: ${pError?.message}`); // 2. Upsert Varga Charts for (const v of parsed.vargaCharts) { await supabase.from('varga_charts').upsert({ profile_id: profile.id, varga_type: v.type, chart_text: v.text }, { onConflict: 'profile_id,varga_type' }); } // 3. Upsert Tabular Data for (const t of parsed.tableData) { await supabase.from('astrological_data').upsert({ profile_id: profile.id, data_type: t.type, content: t.content }, { onConflict: 'profile_id,data_type' }); } return profile.id; } export async function fetchProfileData(profileId: string): Promise { // 1. Fetch the single record from the profiles table const { data: profile, error } = await supabase .from('profiles') .select('*') .eq('id', profileId) .single(); if (error || !profile) { console.error('Error fetching profile from database:', error); return null; } // 2. Fetch Divisional Charts (Varga) const { data: vargas } = await supabase .from('varga_charts') .select('varga_type, chart_text') .eq('profile_id', profileId); const divisionalCharts: Record = {}; vargas?.forEach(v => { if (v.varga_type && v.varga_type !== 'D1') { divisionalCharts[v.varga_type] = v.chart_text || ''; } }); // 3. Fetch Tabular Data (Longitude, Shadbala, Dasha) const { data: tables } = await supabase .from('astrological_data') .select('data_type, content') .eq('profile_id', profileId); const tableMap: Record = {}; tables?.forEach(t => { if (t.data_type) tableMap[t.data_type.toLowerCase()] = t.content || ''; }); const rawShadbala = tableMap['shadbala'] || ''; // (In future phases, we may want to parse Shadbala here, but currently Step0Input parses it locally) // 4. Map the database fields to the AstroData object return { userName: profile.name, dob: profile.dob, birthTime: profile.birth_time, isBirthTimeEstimate: profile.is_birth_time_estimate, longitudeTable: tableMap['longitude_table'] || profile.longitude_table || '', rasiChartText: profile.rasi_chart_text || '', dasha: tableMap['dasha'] || profile.dasha || '', additionalInfo: tableMap['additional_info'] || profile.additional_info || '', divisionalCharts: divisionalCharts, ashtakavarga: profile.ashtakavarga || {}, vargaAshtakavarga: profile.varga_ashtakavarga || {}, savChartType: profile.sav_chart_type || 'D1', transitNatalSelection: profile.transit_natal_selection || 'D1', stepInterpretations: {} }; } /** * updateProfileData synchronizes the current form state (AstroData) * back to its Supabase profile row. */ export async function updateProfileData(profileId: string, data: AstroData) { // 1. Update Profile core table const { error } = await supabase .from('profiles') .update({ name: data.userName, dob: data.dob, birth_time: data.birthTime, is_birth_time_estimate: data.isBirthTimeEstimate, rasi_chart_text: data.rasiChartText, ashtakavarga: data.ashtakavarga, varga_ashtakavarga: data.vargaAshtakavarga, sav_chart_type: data.savChartType, transit_natal_selection: data.transitNatalSelection }) .eq('id', profileId); if (error) { console.error('Error updating profile in database:', error); throw error; } // 2. Sync Divisional Charts if (data.divisionalCharts) { for (const [vType, vText] of Object.entries(data.divisionalCharts)) { if (vText && vText.trim()) { await supabase.from('varga_charts').upsert({ profile_id: profileId, varga_type: vType, chart_text: vText }, { onConflict: 'profile_id,varga_type' }); } } } // 3. Sync Tabular Data const tables = [ { type: 'longitude_table', content: data.longitudeTable }, { type: 'dasha', content: data.dasha }, { type: 'additional_info', content: data.additionalInfo } ]; for (const t of tables) { if (t.content && t.content.trim()) { await supabase.from('astrological_data').upsert({ profile_id: profileId, data_type: t.type, content: t.content }, { onConflict: 'profile_id,data_type' }); } } }