"""
Disease Enrichment Script
Adds description, symptoms, and common treatments to existing diseases in MongoDB.
Uses the MedlinePlus Connect API and NLM Clinical Tables API for data.

REVERSIBLE: To undo, run:
    db.diseases.updateMany(
        {source: "icd10_bulk_import"},
        {$unset: {description: "", symptoms: "", commonTreatments: ""}}
    )
"""

import json
import sys
import os
import time
import urllib.request
import urllib.parse
import re
from datetime import datetime

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

from pymongo import MongoClient
from dotenv import load_dotenv

load_dotenv(os.path.join(os.path.dirname(__file__), '..', '.env'))

MONGODB_URI = os.getenv('MONGODB_URI')
MONGODB_DB_NAME = os.getenv('MONGODB_DB_NAME', 'hipograf')


def fetch_medlineplus_info(icd_code):
    """Fetch disease info from MedlinePlus Connect API using ICD-10 code."""
    url = (
        f"https://connect.medlineplus.gov/service"
        f"?mainSearchCriteria.v.cs=2.16.840.1.113883.6.90"
        f"&mainSearchCriteria.v.c={urllib.parse.quote(icd_code)}"
        f"&knowledgeResponseType=application/json"
    )

    try:
        req = urllib.request.Request(url, headers={'User-Agent': 'Hipograf/1.0'})
        with urllib.request.urlopen(req, timeout=15) as resp:
            data = json.loads(resp.read().decode())
            entries = data.get('feed', {}).get('entry', [])
            if entries:
                entry = entries[0]
                title = entry.get('title', {}).get('_value', '')
                summary_html = entry.get('summary', {}).get('_value', '')
                # Strip HTML tags from summary
                summary = re.sub(r'<[^>]+>', '', summary_html).strip()
                # Clean up whitespace
                summary = re.sub(r'\s+', ' ', summary)
                return {
                    'title': title,
                    'summary': summary[:2000] if summary else '',
                }
    except Exception as e:
        pass  # Silent fail, we'll use fallback

    return None


# Curated descriptions for common disease categories by ICD prefix
COMMON_DESCRIPTIONS = {
    'I10': {
        'description': 'A condition in which the force of the blood against the artery walls is too high. Usually defined as blood pressure above 140/90.',
        'symptoms': 'Often asymptomatic. May include headaches, shortness of breath, nosebleeds, dizziness, chest pain, visual changes.',
        'commonTreatments': 'Lifestyle changes (diet, exercise, weight management), ACE inhibitors, ARBs, beta-blockers, calcium channel blockers, diuretics.',
    },
    'E11': {
        'description': 'A chronic condition that affects the way the body processes blood sugar (glucose). The body either resists the effects of insulin or does not produce enough.',
        'symptoms': 'Increased thirst, frequent urination, increased hunger, fatigue, blurred vision, slow-healing sores, frequent infections, numbness or tingling.',
        'commonTreatments': 'Metformin, sulfonylureas, insulin therapy, GLP-1 receptor agonists, lifestyle modifications, blood sugar monitoring.',
    },
    'J45': {
        'description': 'A condition in which the airways narrow, swell, and may produce extra mucus. This can make breathing difficult and trigger coughing, wheezing, and shortness of breath.',
        'symptoms': 'Shortness of breath, chest tightness, wheezing, coughing (especially at night or early morning), difficulty sleeping due to breathing problems.',
        'commonTreatments': 'Inhaled corticosteroids, long-acting beta agonists (LABAs), leukotriene modifiers, short-acting bronchodilators (rescue inhalers), allergen avoidance.',
    },
    'G43': {
        'description': 'A neurological condition characterized by intense, debilitating headaches often accompanied by nausea, vomiting, and sensitivity to light and sound.',
        'symptoms': 'Throbbing or pulsing pain (usually on one side), nausea, vomiting, sensitivity to light and sound, visual disturbances (aura), tingling sensations.',
        'commonTreatments': 'Triptans, NSAIDs, anti-nausea medications, preventive medications (beta-blockers, antidepressants, anti-seizure drugs), CGRP inhibitors.',
    },
    'M54': {
        'description': 'Pain in the lower back region that can result from strain, injury, or underlying conditions affecting the spine, muscles, nerves, or other structures.',
        'symptoms': 'Dull aching or sharp pain in the lower back, muscle stiffness, limited range of motion, pain radiating to the legs, difficulty standing or walking.',
        'commonTreatments': 'Physical therapy, NSAIDs, muscle relaxants, exercise programs, hot/cold therapy, ergonomic adjustments, spinal injections in severe cases.',
    },
    'H52': {
        'description': 'Disorders of refraction and accommodation of the eye, including myopia (nearsightedness), hyperopia (farsightedness), astigmatism, and presbyopia.',
        'symptoms': 'Blurred vision, difficulty focusing, eye strain, headaches, squinting, difficulty seeing at certain distances.',
        'commonTreatments': 'Corrective lenses (glasses or contacts), refractive surgery (LASIK, PRK), regular eye examinations.',
    },
    'L70': {
        'description': 'A skin condition that occurs when hair follicles become clogged with oil and dead skin cells. It causes whiteheads, blackheads, or pimples.',
        'symptoms': 'Whiteheads, blackheads, papules, pustules, nodules, cystic lesions, inflammation, scarring.',
        'commonTreatments': 'Topical retinoids, benzoyl peroxide, salicylic acid, antibiotics (topical or oral), hormonal therapy, isotretinoin for severe cases.',
    },
    'L24': {
        'description': 'Inflammation of the skin caused by direct contact with an irritating substance. It is not an allergic reaction but a response to a substance that damages the skin.',
        'symptoms': 'Red rash, itching, dry or cracked skin, bumps and blisters, swelling, burning or tenderness.',
        'commonTreatments': 'Avoiding irritants, emollients and moisturizers, topical corticosteroids, barrier creams, wet dressings for acute cases.',
    },
}


def get_enrichment_data(icd_code, disease_name):
    """Get enrichment data for a disease, trying multiple sources."""
    base_code = icd_code.split('.')[0]

    # First check curated descriptions
    for code_key in [icd_code, base_code]:
        if code_key in COMMON_DESCRIPTIONS:
            return COMMON_DESCRIPTIONS[code_key]

    # Try MedlinePlus
    info = fetch_medlineplus_info(icd_code)
    if not info and icd_code != base_code:
        info = fetch_medlineplus_info(base_code)

    if info and info.get('summary'):
        return {
            'description': info['summary'][:1000],
            'symptoms': '',
            'commonTreatments': '',
        }

    return None


def main():
    print("=" * 60)
    print("Disease Enrichment Script")
    print("=" * 60)

    client = MongoClient(MONGODB_URI)
    db = client[MONGODB_DB_NAME]
    diseases = db['diseases']

    # Get all diseases that don't have a description yet
    to_enrich = list(diseases.find({
        'source': 'icd10_bulk_import',
        '$or': [
            {'description': {'$exists': False}},
            {'description': ''},
        ]
    }))

    print(f"\nFound {len(to_enrich)} diseases without descriptions.")

    if not to_enrich:
        print("All diseases already enriched!")
        return

    # Prioritize: first enrich diseases that match user's diagnoses
    # (these are the ones that will actually show up in the UI)
    priority_codes = set()
    diagnoses_col = db.get_collection('diagnoses')
    for d in diagnoses_col.find({}, {'icdCode': 1}):
        code = d.get('icdCode', '')
        priority_codes.add(code)
        priority_codes.add(code.split('.')[0])

    priority = [d for d in to_enrich if d['icdCode'] in priority_codes]
    rest = [d for d in to_enrich if d['icdCode'] not in priority_codes]

    print(f"  Priority (matching diagnoses): {len(priority)}")
    print(f"  Remaining: {len(rest)}")

    enriched = 0
    failed = 0

    # Process priority first, then rest (but limit API calls for rest)
    for disease in priority:
        icd_code = disease['icdCode']
        name = disease['name']
        print(f"\n  Enriching [{icd_code}] {name}...")

        data = get_enrichment_data(icd_code, name)
        if data:
            diseases.update_one(
                {'_id': disease['_id']},
                {'$set': {
                    'description': data['description'],
                    'symptoms': data.get('symptoms', ''),
                    'commonTreatments': data.get('commonTreatments', ''),
                    'enrichedAt': datetime.utcnow().isoformat(),
                }}
            )
            enriched += 1
            print(f"    ✓ Enriched ({len(data['description'])} chars)")
        else:
            failed += 1
            print(f"    ✗ No data found")

        time.sleep(0.2)

    # For the rest, batch through with rate limiting (MedlinePlus only)
    MAX_API_CALLS = 200  # Limit to prevent excessive API usage
    api_calls = 0

    for disease in rest:
        if api_calls >= MAX_API_CALLS:
            print(f"\n  Reached API call limit ({MAX_API_CALLS}). Stopping.")
            break

        icd_code = disease['icdCode']
        name = disease['name']

        data = get_enrichment_data(icd_code, name)
        api_calls += 1

        if data:
            diseases.update_one(
                {'_id': disease['_id']},
                {'$set': {
                    'description': data['description'],
                    'symptoms': data.get('symptoms', ''),
                    'commonTreatments': data.get('commonTreatments', ''),
                    'enrichedAt': datetime.utcnow().isoformat(),
                }}
            )
            enriched += 1

        time.sleep(0.3)

        if api_calls % 50 == 0:
            print(f"  Progress: {api_calls} API calls, {enriched} enriched...")

    print(f"\n{'=' * 60}")
    print(f"Enrichment complete!")
    print(f"  Enriched: {enriched}")
    print(f"  Failed: {failed}")
    print(f"  Remaining: {len(to_enrich) - enriched - failed}")
    print(f"\nTo undo:")
    print(f'  db.diseases.updateMany(')
    print(f'    {{source: "icd10_bulk_import"}},')
    print(f'    {{$unset: {{description: "", symptoms: "", commonTreatments: ""}}}}')
    print(f'  )')

    client.close()


if __name__ == '__main__':
    main()
