""" export_tool.py — Assemble and export caregiver data summaries. Combines selected data (meds, appointments, food chart, and an optional document summary) into a formatted text block ready for copy, email, or print. """ from __future__ import annotations import textwrap from datetime import datetime from typing import Optional from config import load_patient_config from med_tracker import get_medications from appointment_tracker import get_upcoming from food_tracker import get_food from profiles import get_profile # ── Core assembler ──────────────────────────────────────────────────────────── def assemble_export( include_meds: bool = True, include_appointments: bool = True, include_food: bool = True, document_summary: Optional[str] = None, custom_note: Optional[str] = None, profile_id: Optional[str] = None, ) -> str: """ Assemble a formatted text export block. Returns a multi-line string suitable for copy-to-clipboard, email body, or print. """ cfg = load_patient_config() today = datetime.now().strftime("%B %d, %Y at %I:%M %p") profile = get_profile(profile_id) if profile_id else None patient_label = "" if profile: patient_label = profile.get("full_name") or profile.get("label") or "" lines = [] # ── Header ────────────────────────────────────────────────────────────── lines.append("=" * 60) lines.append(" CAREGIVER SUMMARY REPORT") lines.append(f" Generated: {today}") if patient_label: lines.append(f" Patient: {patient_label}") elif cfg.get("patient_name"): lines.append(f" Patient: {cfg['patient_name']}") lines.append("=" * 60) lines.append("") # ── Custom note ────────────────────────────────────────────────────────── if custom_note and custom_note.strip(): lines.append("NOTES") lines.append("-" * 40) lines.append(custom_note.strip()) lines.append("") # ── Medications ────────────────────────────────────────────────────────── if include_meds: meds = get_medications(filter="current", profile_id=profile_id) lines.append("CURRENT MEDICATIONS") lines.append("-" * 40) if meds: for med in meds: parts = [med["name"]] if med.get("dosage"): parts.append(med["dosage"]) if med.get("frequency"): parts.append(f"({med['frequency']})") lines.append("• " + " ".join(parts)) if med.get("side_effects"): lines.append(f" ↳ Side effects: {med['side_effects']}") if med.get("personal_notes"): lines.append(f" ↳ Notes: {med['personal_notes']}") else: lines.append("No current medications on file.") lines.append("") # ── Appointments ───────────────────────────────────────────────────────── if include_appointments: appts = get_upcoming(profile_id=profile_id) lines.append("UPCOMING APPOINTMENTS") lines.append("-" * 40) if appts: for appt in appts: date_str = appt.get("date", "") time_str = appt.get("time", "") when = date_str + (f" at {time_str}" if time_str else "") lines.append(f"• {appt['title']} — {when}") if appt.get("location"): lines.append(f" Location: {appt['location']}") if appt.get("notes"): lines.append(f" Notes: {appt['notes']}") else: lines.append("No upcoming appointments.") lines.append("") # ── Food Chart ─────────────────────────────────────────────────────────── if include_food: food_data = get_food(profile_id=profile_id) lines.append("FOOD CHART") lines.append("-" * 40) liked = food_data.get("liked_foods", []) disliked = food_data.get("disliked_foods", []) allergies = food_data.get("allergies", []) if allergies: lines.append("⚠ Allergies:") for e in allergies: note_part = f" ({e['notes']})" if e.get("notes") else "" lines.append(f" • {e['name']}{note_part}") if liked: lines.append("✓ Liked Foods:") for e in liked: note_part = f" ({e['notes']})" if e.get("notes") else "" lines.append(f" • {e['name']}{note_part}") if disliked: lines.append("✗ Disliked Foods:") for e in disliked: note_part = f" ({e['notes']})" if e.get("notes") else "" lines.append(f" • {e['name']}{note_part}") if not allergies and not liked and not disliked: lines.append("No food data on file.") lines.append("") # ── Document Summary ───────────────────────────────────────────────────── if document_summary and document_summary.strip(): lines.append("DOCUMENT SUMMARY") lines.append("-" * 40) # Word-wrap long lines for para in document_summary.strip().split("\n"): wrapped = textwrap.fill(para, width=58) if len(para) > 58 else para lines.append(wrapped) lines.append("") # ── Footer ─────────────────────────────────────────────────────────────── lines.append("=" * 60) lines.append("Built for the Build Small Hackathon — Backyard AI Track") lines.append("All data is stored locally. Nothing leaves this device.") lines.append("=" * 60) return "\n".join(lines) def build_mailto_link( to: str = "", subject: str = "Caregiver Summary Report", body: str = "", ) -> str: """ Build a mailto: URL with pre-filled subject and body. The body is URL-encoded so it works in href attributes. """ import urllib.parse encoded_body = urllib.parse.quote(body) encoded_subject = urllib.parse.quote(subject) return f"mailto:{to}?subject={encoded_subject}&body={encoded_body}"