"""
Create practitioner user records from existing doctor names in diagnoses/hospital_visits,
and create missing hospital visits for unlinked diagnoses.
"""
import os
from datetime import datetime, UTC

from bson import ObjectId
from dotenv import load_dotenv
from pymongo import MongoClient

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

MONGODB_URI = os.getenv('MONGODB_URI', 'mongodb://localhost:27017')
MONGODB_DB_NAME = os.getenv('MONGODB_DB_NAME', 'hipograf')

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

# ── ICD code to specialty mapping ──
ICD_SPECIALTY = {
    'L': 'Dermatoloji',
    'H': 'Göz Hastalıkları',
    'M': 'Fizik Tedavi ve Rehabilitasyon',
    'I': 'Kardiyoloji',
    'E': 'Endokrinoloji',
    'G': 'Nöroloji',
    'J': 'Göğüs Hastalıkları',
    'K': 'Gastroenteroloji',
    'N': 'Üroloji',
    'R': 'Dahiliye',
    'S': 'Ortopedi',
    'T': 'Acil Tıp',
}

# ── ICD code to department mapping ──
ICD_DEPARTMENT = {
    'L': 'Dermatoloji Kliniği',
    'H': 'Göz Kliniği',
    'M': 'FTR Kliniği',
    'I': 'Kardiyoloji Kliniği',
    'E': 'Endokrinoloji Kliniği',
    'G': 'Nöroloji Kliniği',
    'J': 'Göğüs Hastalıkları Kliniği',
}


def get_specialty_for_icd(icd_code: str) -> str:
    """Get specialty from ICD code first letter."""
    if icd_code:
        letter = icd_code[0].upper()
        return ICD_SPECIALTY.get(letter, 'Genel Pratisyen')
    return 'Genel Pratisyen'


def get_department_for_icd(icd_code: str) -> str:
    """Get department from ICD code first letter."""
    if icd_code:
        letter = icd_code[0].upper()
        return ICD_DEPARTMENT.get(letter, 'Genel Poliklinik')
    return 'Genel Poliklinik'


def create_practitioners():
    """Extract unique doctors from diagnoses/visits and create user records."""
    print("\n═══ Creating Practitioner Users ═══\n")

    # Collect unique doctor names and their context
    doctor_info = {}  # name -> {hospitals, specialties, icdCodes}

    # From diagnoses
    diagnoses = list(db.diagnoses.find({}))
    for d in diagnoses:
        name = d.get('practitioner', '').strip()
        if not name:
            continue
        if name not in doctor_info:
            doctor_info[name] = {'hospitals': set(), 'icd_codes': set(), 'clinics': set()}
        doctor_info[name]['hospitals'].add(d.get('hospital', ''))
        doctor_info[name]['icd_codes'].add(d.get('icdCode', ''))
        if d.get('diagnosisClinic'):
            doctor_info[name]['clinics'].add(d['diagnosisClinic'])

    # From hospital visits
    visits = list(db.hospital_visits.find({}))
    for v in visits:
        name = (v.get('doctorName') or '').strip()
        if not name:
            continue
        if name not in doctor_info:
            doctor_info[name] = {'hospitals': set(), 'icd_codes': set(), 'clinics': set()}
        doctor_info[name]['hospitals'].add(v.get('hospital', ''))
        if v.get('department'):
            doctor_info[name]['clinics'].add(v['department'])

    print(f"Found {len(doctor_info)} unique doctor names:")
    for name, info in doctor_info.items():
        print(f"  - {name} | hospitals: {info['hospitals']} | ICD codes: {info['icd_codes']}")

    # Check which already exist as users
    created_count = 0
    for name, info in doctor_info.items():
        existing = db.users.find_one({
            'dispName': name,
            'roles': 'practitioner'
        })
        if existing:
            print(f"  ✓ {name} already exists as practitioner user")
            continue

        # Determine specialty from the ICD codes they've diagnosed
        icd_codes = list(info['icd_codes'])
        specialty = get_specialty_for_icd(icd_codes[0]) if icd_codes else 'Genel Pratisyen'

        # If they have multiple different specialties, pick the most common
        if len(icd_codes) > 1:
            specialty_counts = {}
            for code in icd_codes:
                s = get_specialty_for_icd(code)
                specialty_counts[s] = specialty_counts.get(s, 0) + 1
            specialty = max(specialty_counts, key=specialty_counts.get)

        hospital = list(info['hospitals'])[0] if info['hospitals'] else None
        department = list(info['clinics'])[0] if info['clinics'] else get_department_for_icd(icd_codes[0] if icd_codes else '')

        # Create a safe username from the name
        username = name.lower().replace(' ', '.').replace('ş', 's').replace('ç', 'c') \
            .replace('ğ', 'g').replace('ü', 'u').replace('ö', 'o').replace('ı', 'i') \
            .replace('İ', 'i').replace('Ş', 's').replace('Ç', 'c').replace('Ğ', 'g') \
            .replace('Ü', 'u').replace('Ö', 'o')

        # Remove "dr." prefix from username if present
        if username.startswith('dr.'):
            username = username[3:]

        now = datetime.now(UTC)
        user_doc = {
            'username': username,
            'dispName': name,
            'email': f"{username}@hipograf.health",
            'passwdHash': 'placeholder_not_real_login',  # They won't actually log in yet
            'roles': ['practitioner'],
            'active': True,
            'residentCountry': 'TR',
            'residentCity': 'Ankara',
            'specialty': specialty,
            'hospital': hospital,
            'department': department,
            'title': 'Uzman',
            'phoneNumber': None,
            'bloodType': None,
            'height': None,
            'weight': None,
            'allergies': [],
            'sharingInfo': [],
            'created_at': now,
            'updated_at': now,
        }

        result = db.users.insert_one(user_doc)
        print(f"  ✚ Created practitioner: {name} (specialty: {specialty}, id: {result.inserted_id})")
        created_count += 1

    print(f"\nCreated {created_count} new practitioner users")
    return doctor_info


def create_missing_hospital_visits():
    """Create hospital visits for diagnoses that have no linked visit."""
    print("\n═══ Creating Missing Hospital Visits ═══\n")

    diagnoses = list(db.diagnoses.find({'hospitalVisit': None}))
    # Also check for diagnoses where hospitalVisit field doesn't exist
    diagnoses += list(db.diagnoses.find({'hospitalVisit': {'$exists': False}}))

    # Deduplicate by _id
    seen = set()
    unique_diagnoses = []
    for d in diagnoses:
        if d['_id'] not in seen:
            seen.add(d['_id'])
            unique_diagnoses.append(d)
    diagnoses = unique_diagnoses

    if not diagnoses:
        print("All diagnoses already have hospital visits linked!")
        return

    print(f"Found {len(diagnoses)} diagnoses without hospital visits:")
    created = 0
    for d in diagnoses:
        icd = d.get('icdCode', '?')
        patient_id = d.get('patientId')
        hospital = d.get('hospital', '')
        diag_date = d.get('diagnosisDate')
        practitioner = d.get('practitioner', '')
        clinic = d.get('diagnosisClinic', '')

        # Check if there's already a visit on that date at that hospital
        existing_visit = None
        if diag_date and hospital:
            # Look for visit on same day
            day_start = diag_date.replace(hour=0, minute=0, second=0, microsecond=0)
            day_end = diag_date.replace(hour=23, minute=59, second=59, microsecond=999999)
            existing_visit = db.hospital_visits.find_one({
                'patientId': patient_id,
                'hospital': hospital,
                'visitDate': {'$gte': day_start, '$lte': day_end}
            })

        if existing_visit:
            # Link diagnosis to existing visit
            visit_id = existing_visit['_id']
            db.diagnoses.update_one(
                {'_id': d['_id']},
                {'$set': {'hospitalVisit': visit_id}}
            )
            # Add diagnosis to visit's diagnoses list if not already there
            if d['_id'] not in (existing_visit.get('diagnoses') or []):
                db.hospital_visits.update_one(
                    {'_id': visit_id},
                    {'$addToSet': {'diagnoses': d['_id']}}
                )
            print(f"  → Linked {icd} to existing visit {visit_id}")
        else:
            # Create new hospital visit
            # Look up disease name for reason
            disease = db.diseases.find_one({'icdCode': icd})
            if not disease:
                base = icd.split('.')[0]
                disease = db.diseases.find_one({'icdCode': base})
            disease_name = disease.get('name', icd) if disease else icd

            now = datetime.now(UTC)
            visit_doc = {
                'patientId': patient_id,
                'hospital': hospital,
                'visitDate': diag_date or now,
                'admissionDate': diag_date,
                'dischargeDate': diag_date,  # Same-day visit
                'doctorName': practitioner,
                'department': clinic or get_department_for_icd(icd),
                'reasonForVisit': disease_name,
                'dischargeSummary': None,
                'diagnoses': [d['_id']],
                'created_at': now,
                'updated_at': now,
            }
            result = db.hospital_visits.insert_one(visit_doc)
            visit_id = result.inserted_id

            # Link diagnosis back to this visit
            db.diagnoses.update_one(
                {'_id': d['_id']},
                {'$set': {'hospitalVisit': visit_id}}
            )
            print(f"  ✚ Created visit for {icd} ({disease_name}) at {hospital} → {visit_id}")
            created += 1

    print(f"\nCreated {created} new hospital visits")


def link_tests_and_vaccinations():
    """Link existing tests and vaccinations to hospital visits by matching dates."""
    print("\n═══ Linking Tests & Vaccinations to Hospital Visits ═══\n")

    # Link tests
    tests = list(db.tests.find({'hospitalVisitId': {'$exists': False}}))
    tests += list(db.tests.find({'hospitalVisitId': None}))
    seen = set()
    unique_tests = []
    for t in tests:
        if t['_id'] not in seen:
            seen.add(t['_id'])
            unique_tests.append(t)

    linked_tests = 0
    for t in unique_tests:
        test_date = t.get('testDate') or t.get('date')
        patient_id = t.get('patientId')
        if not test_date or not patient_id:
            continue

        # Find visit within same day
        day_start = test_date.replace(hour=0, minute=0, second=0, microsecond=0)
        day_end = test_date.replace(hour=23, minute=59, second=59, microsecond=999999)
        visit = db.hospital_visits.find_one({
            'patientId': patient_id,
            'visitDate': {'$gte': day_start, '$lte': day_end}
        })
        if visit:
            db.tests.update_one(
                {'_id': t['_id']},
                {'$set': {'hospitalVisitId': visit['_id']}}
            )
            linked_tests += 1

    print(f"Linked {linked_tests}/{len(unique_tests)} tests to hospital visits")

    # Link vaccinations
    vaccs = list(db.vaccinations.find({'hospitalVisitId': {'$exists': False}}))
    vaccs += list(db.vaccinations.find({'hospitalVisitId': None}))
    seen = set()
    unique_vaccs = []
    for v in vaccs:
        if v['_id'] not in seen:
            seen.add(v['_id'])
            unique_vaccs.append(v)

    linked_vaccs = 0
    for v in unique_vaccs:
        vacc_date = v.get('administeredDate') or v.get('date')
        patient_id = v.get('patientId')
        if not vacc_date or not patient_id:
            continue

        day_start = vacc_date.replace(hour=0, minute=0, second=0, microsecond=0)
        day_end = vacc_date.replace(hour=23, minute=59, second=59, microsecond=999999)
        visit = db.hospital_visits.find_one({
            'patientId': patient_id,
            'visitDate': {'$gte': day_start, '$lte': day_end}
        })
        if visit:
            db.vaccinations.update_one(
                {'_id': v['_id']},
                {'$set': {'hospitalVisitId': visit['_id']}}
            )
            linked_vaccs += 1

    print(f"Linked {linked_vaccs}/{len(unique_vaccs)} vaccinations to hospital visits")


def print_summary():
    """Print a summary of all collections and their connections."""
    print("\n═══ Database Connection Summary ═══\n")
    collections = ['users', 'diagnoses', 'hospitalVisits', 'prescriptions',
                    'tests', 'vaccinations', 'diseases', 'medications', 'operations']
    for col in collections:
        count = db[col].count_documents({})
        print(f"  {col}: {count} documents")

    # Practitioner users
    prac_count = db.users.count_documents({'roles': 'practitioner'})
    print(f"\n  Practitioner users: {prac_count}")

    # Linked diagnoses
    linked = db.diagnoses.count_documents({'hospitalVisit': {'$ne': None}})
    total = db.diagnoses.count_documents({})
    print(f"  Diagnoses with hospital visit: {linked}/{total}")

    # Linked tests
    linked_t = db.tests.count_documents({'hospitalVisitId': {'$ne': None}})
    total_t = db.tests.count_documents({})
    print(f"  Tests with hospital visit: {linked_t}/{total_t}")

    # Linked vaccinations
    linked_v = db.vaccinations.count_documents({'hospitalVisitId': {'$ne': None}})
    total_v = db.vaccinations.count_documents({})
    print(f"  Vaccinations with hospital visit: {linked_v}/{total_v}")

    # Prescriptions with diagnosis
    linked_p = db.prescriptions.count_documents({'diagnosisId': {'$ne': None}})
    total_p = db.prescriptions.count_documents({})
    print(f"  Prescriptions with diagnosis: {linked_p}/{total_p}")


if __name__ == '__main__':
    create_practitioners()
    create_missing_hospital_visits()
    link_tests_and_vaccinations()
    print_summary()
    client.close()
    print("\n✓ Done!")
