"""
ICD-10 Disease Import Script (Full version)
Uses more granular search prefixes to get past the 500-per-query API limit.

REVERSIBLE: db.diseases.drop()
"""

import json
import sys
import os
import urllib.request
import string
from datetime import datetime, timezone

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')

# ICD-10 chapter -> body region mapping
BODY_REGION_MAP = [
    ("A00", "B99", "whole body"),
    ("C00", "C14", "head/neck"), ("C15", "C26", "digestive"),
    ("C30", "C39", "lungs"), ("C40", "C41", "bones"),
    ("C43", "C44", "skin"), ("C45", "C49", "soft tissue"),
    ("C50", "C50", "breast"), ("C51", "C58", "reproductive"),
    ("C60", "C63", "reproductive"), ("C64", "C68", "urinary"),
    ("C69", "C72", "brain/nerves"), ("C73", "C75", "endocrine"),
    ("C76", "C80", "whole body"), ("C81", "C96", "blood/lymph"),
    ("D00", "D48", "whole body"), ("D49", "D49", "whole body"),
    ("D50", "D89", "blood"),
    ("E00", "E07", "thyroid"), ("E08", "E13", "pancreas"),
    ("E15", "E16", "pancreas"), ("E20", "E35", "endocrine"),
    ("E36", "E36", "endocrine"), ("E40", "E46", "whole body"),
    ("E50", "E64", "whole body"), ("E65", "E68", "whole body"),
    ("E70", "E88", "whole body"), ("E89", "E89", "endocrine"),
    ("F01", "F99", "brain"),
    ("G00", "G09", "brain"), ("G10", "G14", "brain"),
    ("G20", "G26", "brain"), ("G30", "G32", "brain"),
    ("G35", "G37", "brain/nerves"), ("G40", "G47", "brain"),
    ("G50", "G59", "nerves"), ("G60", "G65", "nerves"),
    ("G70", "G73", "muscles/nerves"), ("G80", "G83", "brain"),
    ("G89", "G99", "brain/nerves"),
    ("H00", "H59", "eye"), ("H60", "H95", "ear"),
    ("I00", "I09", "heart"), ("I10", "I16", "heart"),
    ("I20", "I25", "heart"), ("I26", "I28", "heart/lungs"),
    ("I30", "I52", "heart"), ("I60", "I69", "brain"),
    ("I70", "I79", "blood vessels"), ("I80", "I89", "blood vessels"),
    ("I95", "I99", "heart"),
    ("J00", "J06", "throat/nose"), ("J09", "J18", "lungs"),
    ("J20", "J22", "lungs"), ("J30", "J39", "throat/nose"),
    ("J40", "J47", "lungs"), ("J60", "J70", "lungs"),
    ("J80", "J99", "lungs"),
    ("K00", "K14", "mouth/teeth"), ("K20", "K31", "stomach"),
    ("K35", "K38", "abdomen"), ("K40", "K46", "abdomen"),
    ("K50", "K52", "intestines"), ("K55", "K64", "intestines"),
    ("K65", "K68", "abdomen"), ("K70", "K77", "liver"),
    ("K80", "K87", "gallbladder"), ("K90", "K95", "digestive"),
    ("L00", "L99", "skin"),
    ("M00", "M25", "joints"), ("M26", "M27", "jaw"),
    ("M30", "M36", "soft tissue"), ("M40", "M54", "spine"),
    ("M60", "M63", "muscles"), ("M65", "M67", "tendons"),
    ("M70", "M79", "soft tissue"), ("M80", "M94", "bones"),
    ("M95", "M99", "musculoskeletal"),
    ("N00", "N29", "kidneys"), ("N30", "N39", "bladder/urinary"),
    ("N40", "N53", "reproductive"), ("N60", "N65", "breast"),
    ("N70", "N98", "reproductive"), ("N99", "N99", "urinary"),
    ("O00", "O9A", "reproductive"),
    ("P00", "P96", "whole body"),
    ("Q00", "Q07", "brain"), ("Q10", "Q18", "head/neck"),
    ("Q20", "Q28", "heart"), ("Q30", "Q34", "lungs"),
    ("Q35", "Q37", "mouth"), ("Q38", "Q45", "digestive"),
    ("Q50", "Q56", "reproductive"), ("Q60", "Q64", "urinary"),
    ("Q65", "Q79", "musculoskeletal"), ("Q80", "Q99", "whole body"),
    ("R00", "R09", "heart/lungs"), ("R10", "R19", "abdomen"),
    ("R20", "R23", "skin/nerves"), ("R25", "R29", "musculoskeletal"),
    ("R30", "R39", "urinary"), ("R40", "R46", "brain"),
    ("R47", "R49", "throat"), ("R50", "R69", "whole body"),
    ("R70", "R79", "blood"), ("R80", "R82", "urinary"),
    ("R83", "R99", "whole body"),
    ("S00", "S09", "head"), ("S10", "S19", "neck"),
    ("S20", "S29", "chest"), ("S30", "S39", "abdomen"),
    ("S40", "S49", "shoulder/arm"), ("S50", "S59", "elbow/forearm"),
    ("S60", "S69", "wrist/hand"), ("S70", "S79", "hip/thigh"),
    ("S80", "S89", "knee/leg"), ("S90", "S99", "ankle/foot"),
    ("T07", "T88", "whole body"),
    ("V00", "Y99", "external"),
    ("Z00", "Z99", "health services"),
]


def get_body_region(code):
    code_clean = code.upper().replace(".", "")
    for start, end, region in BODY_REGION_MAP:
        s = start.replace(".", "")
        e = end.replace(".", "")
        if s <= code_clean <= e + "ZZZ":
            return region
    return "unspecified"


def fetch_codes_for_prefix(prefix):
    """Fetch codes from NLM API for a given prefix."""
    url = (
        f"https://clinicaltables.nlm.nih.gov/api/icd10cm/v3/search"
        f"?sf=code,name&terms={prefix}&maxList=500"
    )
    try:
        req = urllib.request.Request(url)
        with urllib.request.urlopen(req, timeout=30) as response:
            data = json.loads(response.read().decode())
            if len(data) > 3 and data[3]:
                return [(item[0], item[1]) for item in data[3]]
    except Exception as e:
        print(f"  Warning: Failed for prefix '{prefix}': {e}")
    return []


def main():
    print("=" * 60)
    print("ICD-10 Disease Import Script (Full)")
    print("=" * 60)

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

    # Clear previous import
    existing = db.diseases.count_documents({"source": "icd10_bulk_import"})
    if existing > 0:
        print(f"Clearing {existing} existing imported diseases...")
        db.diseases.delete_many({"source": "icd10_bulk_import"})

    # Use two-character prefixes for letters with many codes
    # This gets us past the 500-per-query limit
    all_codes = {}

    # Disease-relevant letter prefixes (skip V-Y external causes, Z health services)
    disease_letters = "ABCDEFGHIJKLMNOPQRST"

    for letter in disease_letters:
        # First try single letter
        codes = fetch_codes_for_prefix(letter)
        print(f"  {letter}: {len(codes)} codes", end="")

        if len(codes) >= 499:
            # API limit hit - use two-char prefixes
            print(" (limit hit, expanding...)")
            codes = []
            for digit in "0123456789":
                sub = fetch_codes_for_prefix(f"{letter}{digit}")
                codes.extend(sub)
                if sub:
                    print(f"    {letter}{digit}: {len(sub)} codes")
        else:
            print()

        for code, name in codes:
            cat = code[:3]
            if cat not in all_codes and len(cat) == 3:
                all_codes[cat] = name

    print(f"\nTotal unique category codes: {len(all_codes)}")

    # Build disease documents
    diseases = []
    for code in sorted(all_codes.keys()):
        region = get_body_region(code)
        if region in ("external", "health services"):
            continue
        diseases.append({
            "icdCode": code,
            "name": all_codes[code],
            "bodyRegion": region,
            "source": "icd10_bulk_import",
            "importedAt": datetime.now(timezone.utc).isoformat()
        })

    print(f"Inserting {len(diseases)} diseases (excluded external causes & health services)...")

    if diseases:
        result = db.diseases.insert_many(diseases)
        print(f"Inserted {len(result.inserted_ids)} diseases")

    # Summary
    print("\n" + "=" * 60)
    print("Body region summary:")
    print("=" * 60)
    regions = {}
    for d in diseases:
        r = d["bodyRegion"]
        regions[r] = regions.get(r, 0) + 1
    for region, count in sorted(regions.items(), key=lambda x: -x[1]):
        print(f"  {region:25s} {count:4d}")
    print(f"  {'TOTAL':25s} {len(diseases):4d}")

    print("\nTo undo: db.diseases.drop()")
    client.close()


if __name__ == "__main__":
    main()
