"""
HAD Digital - Database-Backed API Server
Supports: report uploads, symptom/dose/vital tracking, daily readings
"""
import http.server
import socketserver
import json
import sqlite3
import os
import hashlib
import uuid
from pathlib import Path
from datetime import datetime
from urllib.parse import urlparse

PORT = 9000
HOST = "127.0.0.1"
BASE_DIR = Path(__file__).parent
DB_PATH = BASE_DIR / "data" / "had.db"
UPLOAD_DIR = BASE_DIR / "uploads"
STATIC_DIR = BASE_DIR / "static"

UPLOAD_DIR.mkdir(exist_ok=True)
STATIC_DIR.mkdir(exist_ok=True)
(BASE_DIR / "data").mkdir(exist_ok=True)

def init_db():
    conn = sqlite3.connect(str(DB_PATH))
    conn.row_factory = sqlite3.Row
    conn.execute("PRAGMA journal_mode=WAL")
    conn.execute("PRAGMA foreign_keys=ON")
    conn.executescript("""
        CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT,username TEXT UNIQUE NOT NULL,password_hash TEXT NOT NULL,salt TEXT NOT NULL,role TEXT NOT NULL CHECK(role IN ('admin','doctor','nurse','patient')),display_name TEXT NOT NULL,email TEXT,phone TEXT,created_at TEXT DEFAULT CURRENT_TIMESTAMP,active INTEGER DEFAULT 1);
        CREATE TABLE IF NOT EXISTS patients (id INTEGER PRIMARY KEY AUTOINCREMENT,user_id INTEGER REFERENCES users(id),display_name TEXT NOT NULL,age INTEGER,cancer_type TEXT,stage TEXT,had_start TEXT,had_end TEXT,status TEXT DEFAULT 'active',assigned_doctor_id INTEGER REFERENCES users(id),assigned_nurse_id INTEGER REFERENCES users(id),emergency_contact TEXT,emergency_phone TEXT,address TEXT,notes TEXT,created_at TEXT DEFAULT CURRENT_TIMESTAMP);
        CREATE TABLE IF NOT EXISTS treatment_protocols (id INTEGER PRIMARY KEY AUTOINCREMENT,patient_id INTEGER REFERENCES patients(id),protocol_name TEXT NOT NULL,drug_name TEXT,dosage TEXT,frequency TEXT,route TEXT,start_date TEXT,end_date TEXT,status TEXT DEFAULT 'active',prescribed_by INTEGER REFERENCES users(id),notes TEXT,created_at TEXT DEFAULT CURRENT_TIMESTAMP);
        CREATE TABLE IF NOT EXISTS medication_schedule (id INTEGER PRIMARY KEY AUTOINCREMENT,patient_id INTEGER REFERENCES patients(id),drug_name TEXT NOT NULL,dosage TEXT NOT NULL,unit TEXT,scheduled_time TEXT NOT NULL,frequency TEXT DEFAULT 'daily',instructions TEXT,active INTEGER DEFAULT 1);
        CREATE TABLE IF NOT EXISTS dose_log (id INTEGER PRIMARY KEY AUTOINCREMENT,patient_id INTEGER REFERENCES patients(id),medication_id INTEGER REFERENCES medication_schedule(id),drug_name TEXT NOT NULL,dosage_taken TEXT NOT NULL,scheduled_time TEXT,actual_time TEXT DEFAULT CURRENT_TIMESTAMP,taken_on_time INTEGER DEFAULT 1,notes TEXT,reported_by INTEGER REFERENCES users(id),created_at TEXT DEFAULT CURRENT_TIMESTAMP);
        CREATE TABLE IF NOT EXISTS symptom_reports (id INTEGER PRIMARY KEY AUTOINCREMENT,patient_id INTEGER REFERENCES patients(id),symptom TEXT NOT NULL,grade INTEGER CHECK(grade BETWEEN 0 AND 4),severity TEXT,description TEXT,onset_time TEXT,duration TEXT,provisional INTEGER DEFAULT 0,notes TEXT,reported_by INTEGER REFERENCES users(id),reviewed_by INTEGER REFERENCES users(id),reviewed_at TEXT,created_at TEXT DEFAULT CURRENT_TIMESTAMP);
        CREATE TABLE IF NOT EXISTS vital_signs (id INTEGER PRIMARY KEY AUTOINCREMENT,patient_id INTEGER REFERENCES patients(id),measurement_type TEXT NOT NULL,value REAL NOT NULL,unit TEXT NOT NULL,measured_at TEXT DEFAULT CURRENT_TIMESTAMP,notes TEXT,reported_by INTEGER REFERENCES users(id),abnormal INTEGER DEFAULT 0,created_at TEXT DEFAULT CURRENT_TIMESTAMP);
        CREATE TABLE IF NOT EXISTS daily_readings (id INTEGER PRIMARY KEY AUTOINCREMENT,patient_id INTEGER REFERENCES patients(id),reading_date TEXT NOT NULL,weight_kg REAL,temperature_c REAL,blood_pressure_sys INTEGER,blood_pressure_dia INTEGER,heart_rate INTEGER,oxygen_saturation REAL,pain_score INTEGER CHECK(pain_score BETWEEN 0 AND 10),fatigue_score INTEGER CHECK(fatigue_score BETWEEN 0 AND 10),appetite_score INTEGER CHECK(appetite_score BETWEEN 0 AND 10),sleep_hours REAL,fluid_intake_ml INTEGER,urine_output_ml INTEGER,stool_count INTEGER,notes TEXT,reported_by INTEGER REFERENCES users(id),created_at TEXT DEFAULT CURRENT_TIMESTAMP,UNIQUE(patient_id,reading_date));
        CREATE TABLE IF NOT EXISTS reports (id INTEGER PRIMARY KEY AUTOINCREMENT,patient_id INTEGER REFERENCES patients(id),report_type TEXT NOT NULL CHECK(report_type IN ('lab','imaging','pathology','discharge','referral','other')),title TEXT NOT NULL,description TEXT,file_path TEXT NOT NULL,file_name TEXT NOT NULL,file_size INTEGER,mime_type TEXT,uploaded_by INTEGER REFERENCES users(id),reviewed INTEGER DEFAULT 0,reviewed_by INTEGER REFERENCES users(id),reviewed_at TEXT,created_at TEXT DEFAULT CURRENT_TIMESTAMP);
        CREATE TABLE IF NOT EXISTS alerts (id INTEGER PRIMARY KEY AUTOINCREMENT,patient_id INTEGER REFERENCES patients(id),alert_type TEXT NOT NULL,severity TEXT CHECK(severity IN ('info','low','medium','high','critical')),message TEXT NOT NULL,details TEXT,status TEXT DEFAULT 'active',acknowledged_by INTEGER REFERENCES users(id),acknowledged_at TEXT,resolved_by INTEGER REFERENCES users(id),resolved_at TEXT,created_at TEXT DEFAULT CURRENT_TIMESTAMP);
        CREATE TABLE IF NOT EXISTS messages (id INTEGER PRIMARY KEY AUTOINCREMENT,patient_id INTEGER REFERENCES patients(id),sender_id INTEGER REFERENCES users(id),recipient_id INTEGER REFERENCES users(id),subject TEXT,message TEXT NOT NULL,read INTEGER DEFAULT 0,read_at TEXT,created_at TEXT DEFAULT CURRENT_TIMESTAMP);
        CREATE TABLE IF NOT EXISTS audit_log (id INTEGER PRIMARY KEY AUTOINCREMENT,user_id INTEGER,action TEXT NOT NULL,entity_type TEXT,entity_id INTEGER,details TEXT,ip_address TEXT,created_at TEXT DEFAULT CURRENT_TIMESTAMP);
        CREATE INDEX IF NOT EXISTS idx_dose_log_patient ON dose_log(patient_id,created_at);
        CREATE INDEX IF NOT EXISTS idx_symptom_patient ON symptom_reports(patient_id,created_at);
        CREATE INDEX IF NOT EXISTS idx_vitals_patient ON vital_signs(patient_id,measured_at);
        CREATE INDEX IF NOT EXISTS idx_daily_readings ON daily_readings(patient_id,reading_date);
        CREATE INDEX IF NOT EXISTS idx_alerts_patient ON alerts(patient_id,status);
        CREATE INDEX IF NOT EXISTS idx_reports_patient ON reports(patient_id,report_type);
    """)
    if conn.execute("SELECT COUNT(*) FROM users").fetchone()[0]==0:
        seed_demo_data(conn)
    conn.commit()
    conn.close()

def seed_demo_data(conn):
    print("Seeding demo data...")
    users_data = [
        ("admin", "admin123", "admin", "Marie Dupont", "admin@had.fr", "+33123456789"),
        ("dr.martin", "demo123", "doctor", "Dr. Sophie Martin", "martin@had.fr", "+33123456790"),
        ("inf.moret", "demo123", "nurse", "Inf. Claire Moret", "moret@had.fr", "+33123456791"),
        ("patient.durand", "demo123", "patient", "Jean Durand", "durand@email.fr", "+33123456792"),
        ("patient.laurent", "demo123", "patient", "Marie Laurent", "laurent@email.fr", "+33123456793"),
        ("patient.moreau", "demo123", "patient", "Pierre Moreau", "moreau@email.fr", "+33123456794"),
    ]
    for u, p, r, d, e, ph in users_data:
        salt = os.urandom(16).hex()
        h = hashlib.scrypt(p.encode(), salt=salt.encode(), n=2**14, r=8, p=1, dklen=64).hex()
        conn.execute("INSERT INTO users (username, password_hash, salt, role, display_name, email, phone) VALUES (?,?,?,?,?,?,?)", (u, h, salt, r, d, e, ph))
    
    patients_data = [
        (4, "Jean Durand", 62, "Lung", "IIIA", "2026-08-15", None, "active", 2, 3),
        (5, "Marie Laurent", 55, "Breast", "IIB", "2026-08-20", None, "active", 2, 3),
        (6, "Pierre Moreau", 70, "Colorectal", "IIIB", "2026-08-25", None, "active", 2, 3),
    ]
    for uid, name, age, cancer, stage, start, end, status, doc, nurse in patients_data:
        conn.execute("INSERT INTO patients (user_id, display_name, age, cancer_type, stage, had_start, had_end, status, assigned_doctor_id, assigned_nurse_id) VALUES (?,?,?,?,?,?,?,?,?,?)", (uid, name, age, cancer, stage, start, end, status, doc, nurse))
    
    meds_data = [
        (1, "Ondansetron", "8", "mg", "08:00", "twice_daily", "Take with water"),
        (1, "Ondansetron", "8", "mg", "20:00", "twice_daily", "Take with water"),
        (1, "Dexamethasone", "4", "mg", "08:00", "daily", "Take with food"),
        (1, "Metoclopramide", "10", "mg", "08:00", "three_daily", "Before meals"),
        (1, "Metoclopramide", "10", "mg", "13:00", "three_daily", "Before meals"),
        (1, "Metoclopramide", "10", "mg", "19:00", "three_daily", "Before meals"),
        (2, "Tamoxifen", "20", "mg", "09:00", "daily", "With breakfast"),
        (2, "Calcium", "500", "mg", "09:00", "twice_daily", "With vitamin D"),
        (2, "Calcium", "500", "mg", "21:00", "twice_daily", "With vitamin D"),
        (3, "Capecitabine", "1500", "mg", "08:00", "twice_daily", "After meals"),
        (3, "Capecitabine", "1500", "mg", "20:00", "twice_daily", "After meals"),
        (3, "Loperamide", "4", "mg", "as_needed", "prn", "For diarrhea >3 episodes"),
    ]
    for pid, name, dose, unit, time, freq, instr in meds_data:
        conn.execute("INSERT INTO medication_schedule (patient_id, drug_name, dosage, unit, scheduled_time, frequency, instructions) VALUES (?,?,?,?,?,?,?)", (pid, name, dose, unit, time, freq, instr))
    
    dose_logs = [
        (1, 1, "Ondansetron", "8mg", "08:00", "2026-09-05 08:05", 1, None, 3),
        (1, 3, "Dexamethasone", "4mg", "08:00", "2026-09-05 08:05", 1, None, 3),
        (1, 4, "Metoclopramide", "10mg", "08:00", "2026-09-05 08:10", 1, None, 3),
        (1, 5, "Metoclopramide", "10mg", "13:00", "2026-09-05 13:00", 1, None, 3),
        (1, 1, "Ondansetron", "8mg", "20:00", "2026-09-05 20:15", 1, "Slight delay", 3),
        (2, 7, "Tamoxifen", "20mg", "09:00", "2026-09-05 09:00", 1, None, 4),
        (3, 10, "Capecitabine", "1500mg", "08:00", "2026-09-05 08:30", 1, None, 5),
    ]
    for pid, mid, drug, dose, sched, actual, ontime, notes, by in dose_logs:
        conn.execute("INSERT INTO dose_log (patient_id, medication_id, drug_name, dosage_taken, scheduled_time, actual_time, taken_on_time, notes, reported_by) VALUES (?,?,?,?,?,?,?,?,?)", (pid, mid, drug, dose, sched, actual, ontime, notes, by))
    
    symptoms = [
        (1, "Nausea", 2, "moderate", "Moderate nausea after chemotherapy", "2026-09-05 10:00", "2 hours", 0, "Managed with ondansetron", 3, None, None),
        (1, "Skin Rash", 1, "mild", "Macules/papules <10% BSA", "2026-09-04 14:00", "Persistent", 0, "Monitoring", 3, 2, "2026-09-05 09:00"),
        (2, "Fatigue", 2, "moderate", "Limiting instrumental ADL", "2026-09-05 08:00", "All day", 0, "Rest recommended", 4, None, None),
        (2, "Neuropathy", 1, "mild", "Mild paresthesia in fingers", "2026-09-03 16:00", "Intermittent", 0, "Common with taxanes", 4, 2, "2026-09-04 10:00"),
        (3, "Diarrhea", 3, "severe", "6+ stools/day over baseline", "2026-09-05 06:00", "6 hours", 1, "URGENT: Severe diarrhea", 5, None, None),
        (3, "Mucositis", 1, "mild", "Oral mucosa erythema", "2026-09-04 20:00", "Persistent", 0, "Salt water rinse prescribed", 5, 2, "2026-09-05 08:00"),
    ]
    for pid, sym, grade, sev, desc, onset, dur, prov, notes, by, rev_by, rev_at in symptoms:
        conn.execute("INSERT INTO symptom_reports (patient_id, symptom, grade, severity, description, onset_time, duration, provisional, notes, reported_by, reviewed_by, reviewed_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", (pid, sym, grade, sev, desc, onset, dur, prov, notes, by, rev_by, rev_at))
    
    readings = [
        (1, "2026-09-01", 78.5, 36.8, 120, 80, 72, 98.0, 2, 3, 6, 7.0, 2000, 1500, 2, None, 3),
        (1, "2026-09-02", 78.2, 37.1, 118, 78, 75, 97.5, 3, 4, 5, 6.5, 1800, 1400, 3, "Slight fever", 3),
        (1, "2026-09-03", 78.0, 36.9, 122, 82, 70, 98.2, 2, 3, 6, 7.5, 2200, 1600, 2, None, 3),
        (1, "2026-09-04", 77.8, 36.7, 115, 75, 68, 98.5, 1, 2, 7, 8.0, 2100, 1550, 1, "Feeling better", 3),
        (1, "2026-09-05", 77.5, 37.0, 125, 85, 78, 97.8, 3, 4, 5, 6.0, 1900, 1300, 2, "Nausea after chemo", 3),
        (2, "2026-09-01", 62.0, 36.6, 110, 70, 65, 99.0, 1, 2, 7, 8.0, 2000, 1600, 1, None, 4),
        (2, "2026-09-02", 61.8, 36.8, 112, 72, 68, 98.8, 2, 3, 6, 7.5, 1900, 1500, 1, None, 4),
        (2, "2026-09-03", 61.5, 36.5, 108, 68, 62, 99.2, 1, 2, 7, 8.5, 2100, 1650, 1, None, 4),
        (2, "2026-09-04", 61.3, 36.7, 115, 74, 70, 98.5, 2, 3, 6, 7.0, 1800, 1400, 2, None, 4),
        (2, "2026-09-05", 61.0, 36.9, 118, 76, 72, 98.0, 3, 4, 5, 6.5, 1700, 1300, 2, "Fatigue worse", 4),
        (3, "2026-09-01", 85.0, 37.2, 130, 85, 80, 96.5, 3, 5, 4, 5.5, 2200, 1800, 4, None, 5),
        (3, "2026-09-02", 84.5, 37.5, 135, 88, 82, 96.0, 4, 6, 3, 5.0, 2000, 1600, 5, "Diarrhea starting", 5),
        (3, "2026-09-03", 84.0, 37.8, 128, 82, 85, 95.8, 5, 7, 3, 4.5, 1800, 1400, 6, "Diarrhea worsening", 5),
        (3, "2026-09-04", 83.2, 38.1, 132, 86, 88, 95.5, 6, 8, 2, 4.0, 1600, 1200, 7, "Severe diarrhea", 5),
        (3, "2026-09-05", 82.5, 38.5, 138, 90, 92, 95.0, 8, 9, 1, 3.5, 1400, 1000, 8, "URGENT: Dehydration risk", 5),
    ]
    for pid, date, wt, temp, sys, dia, hr, o2, pain, fatigue, appetite, sleep, fluid, urine, stool, notes, by in readings:
        conn.execute("INSERT INTO daily_readings (patient_id, reading_date, weight_kg, temperature_c, blood_pressure_sys, blood_pressure_dia, heart_rate, oxygen_saturation, pain_score, fatigue_score, appetite_score, sleep_hours, fluid_intake_ml, urine_output_ml, stool_count, notes, reported_by) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", (pid, date, wt, temp, sys, dia, hr, o2, pain, fatigue, appetite, sleep, fluid, urine, stool, notes, by))
    
    alerts_data = [
        (1, "symptom", "medium", "Grade 2 Nausea", "Patient reports moderate nausea after chemotherapy", "active", None, None, None, None),
        (2, "symptom", "low", "Fatigue Monitoring", "Patient reports grade 2 fatigue limiting ADL", "active", None, None, None, None),
        (3, "symptom", "critical", "URGENT: Severe Diarrhea", "Grade 3 diarrhea with dehydration risk. Immediate assessment required.", "active", None, None, None, None),
        (3, "vital", "high", "Elevated Temperature", "Patient temperature 38.5C, trending upward for 3 days", "active", None, None, None, None),
        (3, "vital", "high", "Weight Loss Alert", "Patient lost 2.5kg in 5 days, possible dehydration", "active", None, None, None, None),
    ]
    for pid, atype, sev, msg, details, status, ack_by, ack_at, res_by, res_at in alerts_data:
        conn.execute("INSERT INTO alerts (patient_id, alert_type, severity, message, details, status, acknowledged_by, acknowledged_at, resolved_by, resolved_at) VALUES (?,?,?,?,?,?,?,?,?,?)", (pid, atype, sev, msg, details, status, ack_by, ack_at, res_by, res_at))
    
    print("Demo data seeded successfully")

class HADAPIHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        parsed = urlparse(self.path)
        path = parsed.path
        
        if path == '/' or path == '/index.html':
            self.serve_static('HAD_Digital_Mobile.html')
        elif path.startswith('/static/'):
            self.serve_static(path[8:])
        elif path == '/api/health':
            self.json_response({"status": "ok", "version": "2.0.0"})
        elif path == '/api/patients':
            self.get_patients()
        elif path.startswith('/api/patients/') and '/readings' in path:
            self.get_patient_readings(path)
        elif path.startswith('/api/patients/') and '/symptoms' in path:
            self.get_patient_symptoms(path)
        elif path.startswith('/api/patients/') and '/doses' in path:
            self.get_patient_doses(path)
        elif path.startswith('/api/patients/') and '/reports' in path:
            self.get_patient_reports(path)
        elif path.startswith('/api/patients/'):
            self.get_patient_detail(path)
        elif path == '/api/alerts':
            self.get_alerts()
        elif path == '/api/messages':
            self.get_messages()
        elif path == '/api/dashboard':
            self.get_dashboard()
        else:
            self.send_error(404, "Not Found")
    
    def do_POST(self):
        parsed = urlparse(self.path)
        path = parsed.path
        
        if path == '/api/login':
            self.handle_login()
        elif path == '/api/symptoms':
            self.submit_symptom()
        elif path == '/api/doses':
            self.submit_dose()
        elif path == '/api/readings':
            self.submit_reading()
        elif path == '/api/reports/upload':
            self.upload_report()
        elif path == '/api/messages':
            self.send_message()
        elif path.startswith('/api/alerts/') and '/acknowledge' in path:
            self.acknowledge_alert(path)
        else:
            self.send_error(404, "Not Found")
    
    def do_OPTIONS(self):
        self.send_response(200)
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        self.end_headers()
    
    def serve_static(self, filename):
        filepath = STATIC_DIR / filename
        if not filepath.exists():
            self.send_error(404, "File not found")
            return
        
        content_types = {
            '.html': 'text/html',
            '.css': 'text/css',
            '.js': 'application/javascript',
            '.json': 'application/json',
            '.png': 'image/png',
            '.jpg': 'image/jpeg',
            '.svg': 'image/svg+xml',
        }
        ext = filepath.suffix
        content_type = content_types.get(ext, 'application/octet-stream')
        
        self.send_response(200)
        self.send_header('Content-Type', content_type)
        self.end_headers()
        self.wfile.write(filepath.read_bytes())
    
    def get_conn(self):
        conn = sqlite3.connect(str(DB_PATH))
        conn.row_factory = sqlite3.Row
        return conn
    
    def json_response(self, data, status=200):
        self.send_response(status)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()
        self.wfile.write(json.dumps(data).encode())
    
    def read_body(self):
        length = int(self.headers.get('Content-Length', 0))
        return self.rfile.read(length) if length > 0 else b''
    
    def get_patients(self):
        conn = self.get_conn()
        patients = conn.execute("""
            SELECT p.*, 
                   u1.display_name as doctor_name,
                   u2.display_name as nurse_name,
                   (SELECT COUNT(*) FROM alerts a WHERE a.patient_id = p.id AND a.status = 'active') as active_alerts,
                   (SELECT grade FROM symptom_reports sr WHERE sr.patient_id = p.id ORDER BY sr.created_at DESC LIMIT 1) as latest_grade
            FROM patients p
            LEFT JOIN users u1 ON p.assigned_doctor_id = u1.id
            LEFT JOIN users u2 ON p.assigned_nurse_id = u2.id
            WHERE p.status = 'active'
        """).fetchall()
        self.json_response([dict(p) for p in patients])
        conn.close()
    
    def get_patient_detail(self, path):
        pid = int(path.split('/')[3])
        conn = self.get_conn()
        patient = conn.execute("SELECT * FROM patients WHERE id = ?", (pid,)).fetchone()
        if not patient:
            self.json_response({"error": "Patient not found"}, 404)
            conn.close()
            return
        
        vitals = conn.execute("SELECT * FROM daily_readings WHERE patient_id = ? ORDER BY reading_date DESC LIMIT 7", (pid,)).fetchall()
        meds = conn.execute("SELECT * FROM medication_schedule WHERE patient_id = ? AND active = 1 ORDER BY scheduled_time", (pid,)).fetchall()
        symptoms = conn.execute("SELECT * FROM symptom_reports WHERE patient_id = ? ORDER BY created_at DESC LIMIT 10", (pid,)).fetchall()
        alerts = conn.execute("SELECT * FROM alerts WHERE patient_id = ? AND status = 'active' ORDER BY created_at DESC", (pid,)).fetchall()
        
        result = dict(patient)
        result['vitals'] = [dict(v) for v in vitals]
        result['medications'] = [dict(m) for m in meds]
        result['symptoms'] = [dict(s) for s in symptoms]
        result['alerts'] = [dict(a) for a in alerts]
        
        self.json_response(result)
        conn.close()
    
    def get_patient_readings(self, path):
        pid = int(path.split('/')[3])
        conn = self.get_conn()
        readings = conn.execute("SELECT * FROM daily_readings WHERE patient_id = ? ORDER BY reading_date DESC LIMIT 30", (pid,)).fetchall()
        self.json_response([dict(r) for r in readings])
        conn.close()
    
    def get_patient_symptoms(self, path):
        pid = int(path.split('/')[3])
        conn = self.get_conn()
        symptoms = conn.execute("""
            SELECT sr.*, u.display_name as reporter_name
            FROM symptom_reports sr
            LEFT JOIN users u ON sr.reported_by = u.id
            WHERE sr.patient_id = ? 
            ORDER BY sr.created_at DESC LIMIT 30
        """, (pid,)).fetchall()
        self.json_response([dict(s) for s in symptoms])
        conn.close()
    
    def get_patient_doses(self, path):
        pid = int(path.split('/')[3])
        conn = self.get_conn()
        doses = conn.execute("""
            SELECT dl.*, ms.instructions
            FROM dose_log dl
            LEFT JOIN medication_schedule ms ON dl.medication_id = ms.id
            WHERE dl.patient_id = ? 
            ORDER BY dl.actual_time DESC LIMIT 50
        """, (pid,)).fetchall()
        self.json_response([dict(d) for d in doses])
        conn.close()
    
    def get_patient_reports(self, path):
        pid = int(path.split('/')[3])
        conn = self.get_conn()
        reports = conn.execute("""
            SELECT r.*, u.display_name as uploader_name
            FROM reports r
            LEFT JOIN users u ON r.uploaded_by = u.id
            WHERE r.patient_id = ? 
            ORDER BY r.created_at DESC
        """, (pid,)).fetchall()
        self.json_response([dict(r) for r in reports])
        conn.close()
    
    def get_alerts(self):
        conn = self.get_conn()
        alerts = conn.execute("""
            SELECT a.*, p.display_name as patient_name
            FROM alerts a
            JOIN patients p ON a.patient_id = p.id
            WHERE a.status = 'active'
            ORDER BY 
                CASE a.severity 
                    WHEN 'critical' THEN 1 
                    WHEN 'high' THEN 2 
                    WHEN 'medium' THEN 3 
                    WHEN 'low' THEN 4 
                    ELSE 5 
                END,
                a.created_at DESC
        """).fetchall()
        self.json_response([dict(a) for a in alerts])
        conn.close()
    
    def get_messages(self):
        conn = self.get_conn()
        messages = conn.execute("""
            SELECT m.*, u.display_name as sender_name, p.display_name as patient_name
            FROM messages m
            JOIN users u ON m.sender_id = u.id
            LEFT JOIN patients p ON m.patient_id = p.id
            ORDER BY m.created_at DESC LIMIT 20
        """).fetchall()
        self.json_response([dict(m) for m in messages])
        conn.close()
    
    def get_dashboard(self):
        conn = self.get_conn()
        stats = {
            "total_patients": conn.execute("SELECT COUNT(*) FROM patients WHERE status='active'").fetchone()[0],
            "active_alerts": conn.execute("SELECT COUNT(*) FROM alerts WHERE status='active'").fetchone()[0],
            "critical_alerts": conn.execute("SELECT COUNT(*) FROM alerts WHERE status='active' AND severity IN ('critical','high')").fetchone()[0],
            "pending_reviews": conn.execute("SELECT COUNT(*) FROM symptom_reports WHERE reviewed_by IS NULL").fetchone()[0],
            "today_readings": conn.execute("SELECT COUNT(*) FROM daily_readings WHERE reading_date = date('now')").fetchone()[0],
        }
        
        recent_alerts = conn.execute("""
            SELECT a.*, p.display_name as patient_name
            FROM alerts a
            JOIN patients p ON a.patient_id = p.id
            WHERE a.status = 'active'
            ORDER BY a.created_at DESC LIMIT 5
        """).fetchall()
        
        stats['recent_alerts'] = [dict(a) for a in recent_alerts]
        self.json_response(stats)
        conn.close()
    
    def handle_login(self):
        body = json.loads(self.read_body())
        username = body.get('username')
        password = body.get('password')
        
        conn = self.get_conn()
        user = conn.execute("SELECT * FROM users WHERE username = ? AND active = 1", (username,)).fetchone()
        
        if user:
            h = hashlib.scrypt(password.encode(), salt=user['salt'].encode(), n=2**14, r=8, p=1, dklen=64).hex()
            if h == user['password_hash']:
                self.json_response({
                    "success": True,
                    "user": {
                        "id": user['id'],
                        "username": user['username'],
                        "role": user['role'],
                        "name": user['display_name'],
                        "email": user['email']
                    }
                })
                conn.close()
                return
        
        self.json_response({"success": False, "error": "Invalid credentials"}, 401)
        conn.close()
    
    def submit_symptom(self):
        body = json.loads(self.read_body())
        conn = self.get_conn()
        
        conn.execute("""
            INSERT INTO symptom_reports (patient_id, symptom, grade, severity, description, onset_time, duration, provisional, notes, reported_by)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            body['patient_id'],
            body['symptom'],
            body.get('grade', 0),
            body.get('severity', 'mild'),
            body.get('description', ''),
            body.get('onset_time', datetime.now().isoformat()),
            body.get('duration', ''),
            body.get('provisional', 0),
            body.get('notes', ''),
            body.get('reported_by')
        ))
        
        grade = body.get('grade', 0)
        if grade >= 3:
            conn.execute("""
                INSERT INTO alerts (patient_id, alert_type, severity, message, details)
                VALUES (?, 'symptom', 'high', ?, ?)
            """, (
                body['patient_id'],
                f"Grade {grade} {body['symptom']} reported",
                body.get('description', '')
            ))
        
        conn.commit()
        self.json_response({"success": True, "message": "Symptom reported"})
        conn.close()
    
    def submit_dose(self):
        body = json.loads(self.read_body())
        conn = self.get_conn()
        
        conn.execute("""
            INSERT INTO dose_log (patient_id, medication_id, drug_name, dosage_taken, scheduled_time, actual_time, taken_on_time, notes, reported_by)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (
            body['patient_id'],
            body.get('medication_id'),
            body['drug_name'],
            body['dosage_taken'],
            body.get('scheduled_time', ''),
            body.get('actual_time', datetime.now().isoformat()),
            body.get('taken_on_time', 1),
            body.get('notes', ''),
            body.get('reported_by')
        ))
        
        conn.commit()
        self.json_response({"success": True, "message": "Dose recorded"})
        conn.close()
    
    def submit_reading(self):
        body = json.loads(self.read_body())
        conn = self.get_conn()
        
        existing = conn.execute("""
            SELECT id FROM daily_readings 
            WHERE patient_id = ? AND reading_date = ?
        """, (body['patient_id'], body.get('reading_date', datetime.now().strftime('%Y-%m-%d')))).fetchone()
        
        if existing:
            conn.execute("""
                UPDATE daily_readings SET
                    weight_kg = COALESCE(?, weight_kg),
                    temperature_c = COALESCE(?, temperature_c),
                    blood_pressure_sys = COALESCE(?, blood_pressure_sys),
                    blood_pressure_dia = COALESCE(?, blood_pressure_dia),
                    heart_rate = COALESCE(?, heart_rate),
                    oxygen_saturation = COALESCE(?, oxygen_saturation),
                    pain_score = COALESCE(?, pain_score),
                    fatigue_score = COALESCE(?, fatigue_score),
                    appetite_score = COALESCE(?, appetite_score),
                    sleep_hours = COALESCE(?, sleep_hours),
                    fluid_intake_ml = COALESCE(?, fluid_intake_ml),
                    urine_output_ml = COALESCE(?, urine_output_ml),
                    stool_count = COALESCE(?, stool_count),
                    notes = COALESCE(?, notes),
                    reported_by = ?
                WHERE id = ?
            """, (
                body.get('weight_kg'),
                body.get('temperature_c'),
                body.get('blood_pressure_sys'),
                body.get('blood_pressure_dia'),
                body.get('heart_rate'),
                body.get('oxygen_saturation'),
                body.get('pain_score'),
                body.get('fatigue_score'),
                body.get('appetite_score'),
                body.get('sleep_hours'),
                body.get('fluid_intake_ml'),
                body.get('urine_output_ml'),
                body.get('stool_count'),
                body.get('notes'),
                body.get('reported_by'),
                existing['id']
            ))
        else:
            conn.execute("""
                INSERT INTO daily_readings (
                    patient_id, reading_date, weight_kg, temperature_c,
                    blood_pressure_sys, blood_pressure_dia, heart_rate,
                    oxygen_saturation, pain_score, fatigue_score, appetite_score,
                    sleep_hours, fluid_intake_ml, urine_output_ml, stool_count,
                    notes, reported_by
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """, (
                body['patient_id'],
                body.get('reading_date', datetime.now().strftime('%Y-%m-%d')),
                body.get('weight_kg'),
                body.get('temperature_c'),
                body.get('blood_pressure_sys'),
                body.get('blood_pressure_dia'),
                body.get('heart_rate'),
                body.get('oxygen_saturation'),
                body.get('pain_score'),
                body.get('fatigue_score'),
                body.get('appetite_score'),
                body.get('sleep_hours'),
                body.get('fluid_intake_ml'),
                body.get('urine_output_ml'),
                body.get('stool_count'),
                body.get('notes'),
                body.get('reported_by')
            ))
        
        alerts = []
        temp = body.get('temperature_c')
        if temp and temp > 38.0:
            alerts.append(("Elevated Temperature", f"Temperature {temp}C exceeds 38C threshold", "high"))
        
        o2 = body.get('oxygen_saturation')
        if o2 and o2 < 95:
            alerts.append(("Low Oxygen", f"SpO2 {o2}% below 95% threshold", "high"))
        
        hr = body.get('heart_rate')
        if hr and (hr > 100 or hr < 50):
            alerts.append(("Abnormal Heart Rate", f"HR {hr} bpm outside normal range", "medium"))
        
        bp = body.get('blood_pressure_sys')
        if bp and (bp > 140 or bp < 90):
            alerts.append(("Abnormal Blood Pressure", f"Systolic BP {bp} mmHg outside normal range", "medium"))
        
        pain = body.get('pain_score')
        if pain and pain >= 7:
            alerts.append(("Severe Pain", f"Pain score {pain}/10 reported", "high"))
        
        for msg, details, severity in alerts:
            conn.execute("""
                INSERT INTO alerts (patient_id, alert_type, severity, message, details)
                VALUES (?, ?, ?, ?, ?)
            """, (body['patient_id'], 'vital', severity, msg, details))
        
        conn.commit()
        self.json_response({"success": True, "message": "Reading saved", "alerts_generated": len(alerts)})
        conn.close()
    
    def upload_report(self):
        content_type = self.headers.get('Content-Type', '')
        
        if 'multipart/form-data' in content_type:
            boundary = content_type.split('boundary=')[1].encode()
            content_length = int(self.headers.get('Content-Length', 0))
            body = self.rfile.read(content_length)
            
            parts = body.split(b'--' + boundary)
            fields = {}
            file_data = None
            file_name = None
            file_type = None
            
            for part in parts:
                if not part or part.strip() == b'' or part.strip() == b'--':
                    continue
                if b'\r\n\r\n' in part:
                    header, content = part.split(b'\r\n\r\n', 1)
                    if content.endswith(b'\r\n'):
                        content = content[:-2]
                    header_str = header.decode('utf-8', 'replace')
                    if 'filename=' in header_str:
                        fn_start = header_str.find('filename="') + 10
                        fn_end = header_str.find('"', fn_start)
                        file_name = header_str[fn_start:fn_end]
                        ct_start = header_str.find('Content-Type: ') + 14
                        file_type = header_str[ct_start:].strip()
                        file_data = content
                    else:
                        name_start = header_str.find('name="') + 6
                        name_end = header_str.find('"', name_start)
                        field_name = header_str[name_start:name_end]
                        fields[field_name] = content.decode('utf-8', 'replace')
            
            patient_id = fields.get('patient_id')
            report_type = fields.get('report_type', 'other')
            title = fields.get('title', 'Untitled Report')
            description = fields.get('description', '')
            uploaded_by = fields.get('uploaded_by')
            
            if file_data and file_name:
                ext = Path(file_name).suffix
                unique_name = f"{uuid.uuid4().hex}{ext}"
                file_path = UPLOAD_DIR / unique_name
                
                with open(file_path, 'wb') as f:
                    f.write(file_data)
                
                conn = self.get_conn()
                conn.execute("""
                    INSERT INTO reports (patient_id, report_type, title, description, file_path, file_name, file_size, mime_type, uploaded_by)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                """, (patient_id, report_type, title, description, str(file_path), file_name, len(file_data), file_type, uploaded_by))
                conn.commit()
                conn.close()
                
                self.json_response({
                    "success": True,
                    "message": "Report uploaded",
                    "file_name": file_name,
                    "file_size": len(file_data)
                })
                return
        
        self.json_response({"error": "No file provided"}, 400)
    
    def send_message(self):
        body = json.loads(self.read_body())
        conn = self.get_conn()
        
        conn.execute("""
            INSERT INTO messages (patient_id, sender_id, recipient_id, subject, message)
            VALUES (?, ?, ?, ?, ?)
        """, (
            body.get('patient_id'),
            body.get('sender_id'),
            body.get('recipient_id'),
            body.get('subject', ''),
            body['message']
        ))
        
        conn.commit()
        self.json_response({"success": True, "message": "Message sent"})
        conn.close()
    
    def acknowledge_alert(self, path):
        alert_id = int(path.split('/')[3])
        body = json.loads(self.read_body())
        conn = self.get_conn()
        
        conn.execute("""
            UPDATE alerts SET 
                status = 'acknowledged',
                acknowledged_by = ?,
                acknowledged_at = ?
            WHERE id = ?
        """, (body.get('user_id'), datetime.now().isoformat(), alert_id))
        
        conn.commit()
        self.json_response({"success": True, "message": "Alert acknowledged"})
        conn.close()
    
    def log_message(self, format, *args):
        pass

def main():
    init_db()
    
    with socketserver.TCPServer((HOST, PORT), HADAPIHandler) as httpd:
        print(f"HAD Digital API running at http://{HOST}:{PORT}")
        print(f"Database: {DB_PATH}")
        print(f"Uploads: {UPLOAD_DIR}")
        print("Press Ctrl+C to stop")
        
        import webbrowser
        import threading
        threading.Timer(1.5, lambda: webbrowser.open(f"http://{HOST}:{PORT}")).start()
        
        try:
            httpd.serve_forever()
        except KeyboardInterrupt:
            print("\nShutting down...")
            httpd.shutdown()

if __name__ == '__main__':
    main()