import logging import json from datetime import datetime from typing import List, Dict, Optional class PatientHistoryManager: """Complete patient history and wound tracking system""" def __init__(self, database_manager): self.db = database_manager def get_patient_complete_history(self, user_id: int, patient_name: str = None) -> List[Dict]: """Get complete patient history with all wound analyses and images""" try: if patient_name: query = """ SELECT qr.id as response_id, p.name as patient_name, p.age as patient_age, p.gender as patient_gender, qr.response_data, qr.submitted_at as visit_date, w.position as wound_location, w.moisture, w.infection, w.notes, wi.image as image_url, a.analysis_data, a.summary, a.recommendations, a.risk_score, a.risk_level FROM questionnaire_responses qr JOIN patients p ON qr.patient_id = p.id LEFT JOIN wounds w ON w.patient_id = CAST(p.id AS CHAR) LEFT JOIN wound_images wi ON wi.patient_id = CAST(p.id AS CHAR) LEFT JOIN ai_analyses a ON a.questionnaire_id = qr.id WHERE qr.practitioner_id = %s AND p.name = %s ORDER BY qr.submitted_at DESC """ params = (user_id, patient_name) else: query = """ SELECT qr.id as response_id, p.name as patient_name, p.age as patient_age, p.gender as patient_gender, qr.response_data, qr.submitted_at as visit_date, w.position as wound_location, w.moisture, w.infection, w.notes, wi.image as image_url, a.analysis_data, a.summary, a.recommendations, a.risk_score, a.risk_level FROM questionnaire_responses qr JOIN patients p ON qr.patient_id = p.id LEFT JOIN wounds w ON w.patient_id = CAST(p.id AS CHAR) LEFT JOIN wound_images wi ON wi.patient_id = CAST(p.id AS CHAR) LEFT JOIN ai_analyses a ON a.questionnaire_id = qr.id WHERE qr.practitioner_id = %s ORDER BY qr.submitted_at DESC """ params = (user_id,) result = self.db.execute_query(query, params, fetch=True) return result or [] except Exception as e: logging.error(f"Error fetching patient history: {e}") return [] def get_patient_list(self, user_id: int) -> List[Dict]: """Get list of all patients for this practitioner""" try: query = """ SELECT DISTINCT p.name as patient_name, p.age as patient_age, p.gender as patient_gender, COUNT(qr.id) as total_visits, MAX(qr.submitted_at) as last_visit, MIN(qr.submitted_at) as first_visit FROM questionnaire_responses qr JOIN patients p ON qr.patient_id = p.id WHERE qr.practitioner_id = %s GROUP BY p.name, p.age, p.gender ORDER BY last_visit DESC """ result = self.db.execute_query(query, (user_id,), fetch=True) return result or [] except Exception as e: logging.error(f"Error fetching patient list: {e}") return [] def get_wound_progression(self, user_id: int, patient_name: str) -> List[Dict]: """Get wound progression data for timeline visualization""" try: query = """ SELECT qr.submitted_at as visit_date, qr.response_data, w.position as wound_location, w.moisture, w.infection, a.risk_score, a.risk_level, a.summary, wi.image as image_url FROM questionnaire_responses qr JOIN patients p ON qr.patient_id = p.id LEFT JOIN wounds w ON w.patient_id = CAST(p.id AS CHAR) LEFT JOIN wound_images wi ON wi.patient_id = CAST(p.id AS CHAR) LEFT JOIN ai_analyses a ON a.questionnaire_id = qr.id WHERE qr.practitioner_id = %s AND p.name = %s ORDER BY qr.submitted_at ASC """ result = self.db.execute_query(query, (user_id, patient_name), fetch=True) return result or [] except Exception as e: logging.error(f"Error fetching wound progression: {e}") return [] def save_patient_note(self, user_id: int, patient_name: str, note: str) -> bool: """Save a clinical note for a patient""" try: # Check if notes table exists, if not use questionnaires additional_notes query = """ UPDATE questionnaires SET additional_notes = CONCAT(IFNULL(additional_notes, ''), '\n--- Clinical Note (', NOW(), ') ---\n', %s) WHERE user_id = %s AND patient_name = %s ORDER BY created_at DESC LIMIT 1 """ result = self.db.execute_query(query, (note, user_id, patient_name)) return bool(result) except Exception as e: logging.error(f"Error saving patient note: {e}") return False class ReportGenerator: """Professional HTML report generator for wound analysis""" def __init__(self): pass def generate_analysis_report(self, patient_data: Dict, analysis_data: Dict, image_url: str = None) -> str: """Generate comprehensive HTML report for wound analysis""" report_html = f""" SmartHeal AI - Wound Analysis Report

🩺 SmartHeal AI Wound Analysis Report

Advanced AI-Powered Clinical Assessment

Patient Information

Patient Name

{patient_data.get('patient_name', 'N/A')}

Age

{patient_data.get('patient_age', 'N/A')} years

Gender

{patient_data.get('patient_gender', 'N/A')}

Assessment Date

{datetime.now().strftime('%B %d, %Y at %I:%M %p')}

Wound Assessment

Location

{patient_data.get('wound_location', 'N/A')}

Duration

{patient_data.get('wound_duration', 'N/A')}

Pain Level

{patient_data.get('pain_level', 'N/A')}/10

Risk Assessment

{analysis_data.get('risk_level', 'Unknown')} Risk

{f'''

Wound Image

Wound Image
''' if image_url else ''}

AI Analysis Summary

{analysis_data.get('summary', 'No analysis summary available.')}

🎯 Clinical Recommendations

{self._format_recommendations(analysis_data.get('recommendations', ''))}

Medical History

Medical History

{patient_data.get('medical_history', 'None reported')}

Current Medications

{patient_data.get('medications', 'None reported')}

Known Allergies

{patient_data.get('allergies', 'None reported')}

Additional Notes

{patient_data.get('additional_notes', 'None')}

""" return report_html def _format_recommendations(self, recommendations: str) -> str: """Format recommendations as HTML list""" if not recommendations: return "

No specific recommendations available.

" # Split recommendations by common delimiters items = [] for delimiter in ['\n', '. ', '; ']: if delimiter in recommendations: items = [item.strip() for item in recommendations.split(delimiter) if item.strip()] break if not items: items = [recommendations] html = "" return html def generate_patient_history_report(self, patient_history: List[Dict]) -> str: """Generate comprehensive patient history report""" if not patient_history: return "

No patient history available.

" patient_name = patient_history[0].get('patient_name', 'Unknown Patient') html = f"""

📋 Patient History: {patient_name}

Complete Treatment Timeline

""" for i, visit in enumerate(patient_history): visit_date = visit.get('visit_date', '') if isinstance(visit_date, str): try: visit_date = datetime.fromisoformat(visit_date.replace('Z', '+00:00')) except: pass risk_class = f"risk-{visit.get('risk_level', 'unknown').lower()}" html += f"""

Visit #{len(patient_history) - i}

{visit_date.strftime('%B %d, %Y') if hasattr(visit_date, 'strftime') else str(visit_date)}
Location: {visit.get('wound_location', 'N/A')}
Pain Level: {visit.get('pain_level', 'N/A')}/10
Risk: {visit.get('risk_level', 'Unknown')}
{f'

Summary: {visit.get("summary", "No summary available")}

' if visit.get("summary") else ""} {f'

Recommendations: {visit.get("recommendations", "No recommendations available")}

' if visit.get("recommendations") else ""}
""" html += """
""" return html