const express = require('express'); const router = express.Router(); const { getDatabase } = require('../db/init'); // OFA tests that count toward GRCA eligibility const GRCA_REQUIRED = ['hip_ofa', 'hip_pennhip', 'elbow_ofa', 'heart_ofa', 'heart_echo', 'eye_caer']; const GRCA_CORE = { hip: ['hip_ofa', 'hip_pennhip'], elbow: ['elbow_ofa'], heart: ['heart_ofa', 'heart_echo'], eye: ['eye_caer'], }; const VALID_TEST_TYPES = ['hip_ofa', 'hip_pennhip', 'elbow_ofa', 'heart_ofa', 'heart_echo', 'eye_caer', 'thyroid_ofa', 'dna_panel']; // Helper: compute clearance summary for a dog function getClearanceSummary(db, dogId) { const records = db.prepare(` SELECT test_type, ofa_result, ofa_number, expires_at, test_date FROM health_records WHERE dog_id = ? AND test_type IS NOT NULL ORDER BY test_date DESC `).all(dogId); const today = new Date(); const in90 = new Date(); in90.setDate(today.getDate() + 90); const summary = {}; for (const [group, types] of Object.entries(GRCA_CORE)) { const match = records.find(r => types.includes(r.test_type)); if (!match) { summary[group] = { status: 'missing', record: null }; } else { let status = 'pass'; if (match.expires_at) { const exp = new Date(match.expires_at); if (exp < today) status = 'expired'; else if (exp <= in90) status = 'expiring_soon'; } summary[group] = { status, record: match }; } } return summary; } // GET all health records for a dog router.get('/dog/:dogId', (req, res) => { try { const db = getDatabase(); const records = db.prepare(` SELECT * FROM health_records WHERE dog_id = ? ORDER BY test_date DESC `).all(req.params.dogId); res.json(records); } catch (error) { res.status(500).json({ error: error.message }); } }); // GET clearance summary (Hip / Elbow / Heart / Eyes) for a dog router.get('/dog/:dogId/clearance-summary', (req, res) => { try { const db = getDatabase(); const dog = db.prepare('SELECT id, birth_date, chic_number FROM dogs WHERE id = ?').get(req.params.dogId); if (!dog) return res.status(404).json({ error: 'Dog not found' }); const summary = getClearanceSummary(db, dog.id); // Age check: must be >= 24 months for hip/elbow let ageEligible = false; if (dog.birth_date) { const months = (new Date() - new Date(dog.birth_date)) / (1000 * 60 * 60 * 24 * 30.44); ageEligible = months >= 24; } const allPass = Object.values(summary).every(s => ['pass', 'expiring_soon'].includes(s.status)); const grca_eligible = allPass && ageEligible; res.json({ summary, grca_eligible, age_eligible: ageEligible, chic_number: dog.chic_number }); } catch (error) { res.status(500).json({ error: error.message }); } }); // GET CHIC eligibility check router.get('/dog/:dogId/chic-eligible', (req, res) => { try { const db = getDatabase(); const dog = db.prepare('SELECT id, chic_number FROM dogs WHERE id = ?').get(req.params.dogId); if (!dog) return res.status(404).json({ error: 'Dog not found' }); const summary = getClearanceSummary(db, dog.id); const missing = Object.entries(summary) .filter(([, v]) => v.status === 'missing') .map(([k]) => k); res.json({ chic_eligible: missing.length === 0, chic_number: dog.chic_number || null, missing_tests: missing, }); } catch (error) { res.status(500).json({ error: error.message }); } }); // POST create health record router.post('/', (req, res) => { try { const { dog_id, record_type, test_type, test_name, test_date, ofa_result, ofa_number, performed_by, expires_at, document_url, result, vet_name, next_due, notes } = req.body; if (!dog_id || !record_type || !test_date) { return res.status(400).json({ error: 'dog_id, record_type, and test_date are required' }); } if (test_type && !VALID_TEST_TYPES.includes(test_type)) { return res.status(400).json({ error: 'Invalid test_type' }); } const db = getDatabase(); const dbResult = db.prepare(` INSERT INTO health_records (dog_id, record_type, test_type, test_name, test_date, ofa_result, ofa_number, performed_by, expires_at, document_url, result, vet_name, next_due, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `).run( dog_id, record_type, test_type || null, test_name || null, test_date, ofa_result || null, ofa_number || null, performed_by || null, expires_at || null, document_url || null, result || null, vet_name || null, next_due || null, notes || null ); const record = db.prepare('SELECT * FROM health_records WHERE id = ?').get(dbResult.lastInsertRowid); res.status(201).json(record); } catch (error) { res.status(500).json({ error: error.message }); } }); // PUT update health record router.put('/:id', (req, res) => { try { const { record_type, test_type, test_name, test_date, ofa_result, ofa_number, performed_by, expires_at, document_url, result, vet_name, next_due, notes } = req.body; if (test_type && !VALID_TEST_TYPES.includes(test_type)) { return res.status(400).json({ error: 'Invalid test_type' }); } const db = getDatabase(); db.prepare(` UPDATE health_records SET record_type = ?, test_type = ?, test_name = ?, test_date = ?, ofa_result = ?, ofa_number = ?, performed_by = ?, expires_at = ?, document_url = ?, result = ?, vet_name = ?, next_due = ?, notes = ?, updated_at = datetime('now') WHERE id = ? `).run( record_type, test_type || null, test_name || null, test_date, ofa_result || null, ofa_number || null, performed_by || null, expires_at || null, document_url || null, result || null, vet_name || null, next_due || null, notes || null, req.params.id ); const record = db.prepare('SELECT * FROM health_records WHERE id = ?').get(req.params.id); res.json(record); } catch (error) { res.status(500).json({ error: error.message }); } }); // DELETE health record router.delete('/:id', (req, res) => { try { const db = getDatabase(); db.prepare('DELETE FROM health_records WHERE id = ?').run(req.params.id); res.json({ message: 'Health record deleted successfully' }); } catch (error) { res.status(500).json({ error: error.message }); } }); // GET cancer history for a dog router.get('/dog/:dogId/cancer-history', (req, res) => { try { const db = getDatabase(); const records = db.prepare(` SELECT * FROM cancer_history WHERE dog_id = ? ORDER BY age_at_diagnosis ASC, created_at DESC `).all(req.params.dogId); res.json(records); } catch (error) { res.status(500).json({ error: error.message }); } }); // POST create cancer history record router.post('/cancer-history', (req, res) => { try { const { dog_id, cancer_type, age_at_diagnosis, age_at_death, cause_of_death, notes } = req.body; if (!dog_id || !cancer_type) { return res.status(400).json({ error: 'dog_id and cancer_type are required' }); } const db = getDatabase(); // Update dog's age_at_death and cause_of_death if provided if (age_at_death || cause_of_death) { db.prepare(` UPDATE dogs SET age_at_death = COALESCE(?, age_at_death), cause_of_death = COALESCE(?, cause_of_death) WHERE id = ? `).run(age_at_death || null, cause_of_death || null, dog_id); } const dbResult = db.prepare(` INSERT INTO cancer_history (dog_id, cancer_type, age_at_diagnosis, age_at_death, cause_of_death, notes) VALUES (?, ?, ?, ?, ?, ?) `).run( dog_id, cancer_type, age_at_diagnosis || null, age_at_death || null, cause_of_death || null, notes || null ); const record = db.prepare('SELECT * FROM cancer_history WHERE id = ?').get(dbResult.lastInsertRowid); res.status(201).json(record); } catch (error) { res.status(500).json({ error: error.message }); } }); // GET single health record (wildcard should go last to prevent overlap) router.get('/:id', (req, res) => { try { const db = getDatabase(); const record = db.prepare('SELECT * FROM health_records WHERE id = ?').get(req.params.id); if (!record) return res.status(404).json({ error: 'Health record not found' }); res.json(record); } catch (error) { res.status(500).json({ error: error.message }); } }); module.exports = router;