# -*- coding: utf-8 -*-
"""
Script para crear datos de demostración completos para el módulo LIMS.
Incluye órdenes de laboratorio, muestras, pruebas y resultados.
"""

import odoo
from datetime import datetime, timedelta
import random
import logging

_logger = logging.getLogger(__name__)

def create_demo_lab_data(cr):
    """Crea datos completos de demostración para laboratorio"""
    env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
    
    print("\n=== INICIANDO CREACIÓN DE DATOS DE DEMOSTRACIÓN ===")
    
    # Verificar que los parámetros y rangos se cargaron correctamente
    param_count = env['lims.analysis.parameter'].search_count([])
    range_count = env['lims.parameter.range'].search_count([])
    
    print(f"Parámetros encontrados: {param_count}")
    print(f"Rangos de referencia encontrados: {range_count}")
    
    if param_count == 0 or range_count == 0:
        print("⚠️  No se encontraron parámetros o rangos. Asegúrese de que los datos XML se cargaron.")
        return
    
    # Obtener pacientes de demostración
    patients = []
    patient_refs = [
        'lims_management.demo_patient_1',
        'lims_management.demo_patient_2', 
        'lims_management.demo_patient_3',
        'lims_management.demo_patient_4'
    ]
    
    for ref in patient_refs:
        patient = env.ref(ref, raise_if_not_found=False)
        if patient:
            patients.append(patient)
    
    if not patients:
        print("⚠️  No se encontraron pacientes de demostración")
        return
    
    print(f"Pacientes encontrados: {len(patients)}")
    
    # Obtener doctores
    doctors = []
    doctor_refs = ['lims_management.demo_doctor_1', 'lims_management.demo_doctor_2']
    for ref in doctor_refs:
        doctor = env.ref(ref, raise_if_not_found=False)
        if doctor:
            doctors.append(doctor)
    
    if not doctors:
        # Crear un doctor de demo si no existe
        doctors = [env['res.partner'].create({
            'name': 'Dr. Demo',
            'is_doctor': True
        })]
    
    # Obtener análisis disponibles
    analyses = []
    analysis_refs = [
        'lims_management.analysis_hemograma',
        'lims_management.analysis_perfil_lipidico',
        'lims_management.analysis_glucosa',
        'lims_management.analysis_quimica_sanguinea',
        'lims_management.analysis_urianalisis',
        'lims_management.analysis_serologia',
        'lims_management.analysis_urocultivo',
        'lims_management.analysis_tp',
        'lims_management.analysis_prueba_embarazo'
    ]
    
    for ref in analysis_refs:
        analysis = env.ref(ref, raise_if_not_found=False)
        if analysis:
            analyses.append(analysis)
    
    print(f"Análisis encontrados: {len(analyses)}")
    
    if not analyses:
        print("⚠️  No se encontraron análisis de demostración")
        return
    
    # Crear órdenes de laboratorio
    orders_created = []
    
    # Orden 1: Chequeo general para paciente adulto masculino
    if len(patients) > 0 and len(analyses) >= 4:
        order1 = env['sale.order'].create({
            'partner_id': patients[0].id,
            'doctor_id': doctors[0].id if doctors else False,
            'is_lab_request': True,
            # 'lab_request_priority': 'normal',  # Campo no existe aún
            'note': 'Chequeo general anual - Control de salud preventivo',
            'order_line': [
                (0, 0, {
                    'product_id': analyses[0].product_variant_id.id,  # Hemograma
                    'product_uom_qty': 1
                }),
                (0, 0, {
                    'product_id': analyses[1].product_variant_id.id,  # Perfil Lipídico
                    'product_uom_qty': 1
                }),
                (0, 0, {
                    'product_id': analyses[2].product_variant_id.id,  # Glucosa
                    'product_uom_qty': 1
                }),
                (0, 0, {
                    'product_id': analyses[3].product_variant_id.id,  # Química Sanguínea
                    'product_uom_qty': 1
                })
            ]
        })
        order1.action_confirm()
        orders_created.append(order1)
        print(f"✓ Orden {order1.name} creada para {order1.partner_id.name}")
    
    # Orden 2: Control prenatal para paciente embarazada
    if len(patients) > 2 and len(analyses) >= 5:
        # Usar María González (índice 2) que es femenina
        patients[2].is_pregnant = True
        
        order2 = env['sale.order'].create({
            'partner_id': patients[2].id,
            'doctor_id': doctors[-1].id if doctors else False,
            'is_lab_request': True,
            # 'lab_request_priority': 'high',  # Campo no existe aún
            'note': 'Control prenatal - 20 semanas de gestación',
            'order_line': [
                (0, 0, {
                    'product_id': analyses[0].product_variant_id.id,  # Hemograma
                    'product_uom_qty': 1
                }),
                (0, 0, {
                    'product_id': analyses[2].product_variant_id.id,  # Glucosa
                    'product_uom_qty': 1
                }),
                (0, 0, {
                    'product_id': analyses[4].product_variant_id.id if len(analyses) > 4 else analyses[0].product_variant_id.id,  # Urianálisis
                    'product_uom_qty': 1
                }),
                (0, 0, {
                    'product_id': analyses[5].product_variant_id.id if len(analyses) > 5 else analyses[1].product_variant_id.id,  # Serología
                    'product_uom_qty': 1
                })
            ]
        })
        order2.action_confirm()
        orders_created.append(order2)
        print(f"✓ Orden {order2.name} creada para {order2.partner_id.name} (embarazada)")
    
    # Orden 3: Urgencia - Sospecha de infección
    if len(patients) > 1 and len(analyses) >= 3:
        order3 = env['sale.order'].create({
            'partner_id': patients[1].id,
            'doctor_id': doctors[0].id if doctors else False,
            'is_lab_request': True,
            # 'lab_request_priority': 'urgent',  # Campo no existe aún
            'note': 'Urgencia - Fiebre de 39°C, dolor lumbar, sospecha de infección urinaria',
            'order_line': [
                (0, 0, {
                    'product_id': analyses[4].product_variant_id.id if len(analyses) > 4 else analyses[0].product_variant_id.id,  # Urianálisis
                    'product_uom_qty': 1
                }),
                (0, 0, {
                    'product_id': analyses[6].product_variant_id.id if len(analyses) > 6 else analyses[1].product_variant_id.id,  # Urocultivo
                    'product_uom_qty': 1
                }),
                (0, 0, {
                    'product_id': analyses[0].product_variant_id.id,  # Hemograma (para ver leucocitos)
                    'product_uom_qty': 1
                })
            ]
        })
        order3.action_confirm()
        orders_created.append(order3)
        print(f"✓ Orden urgente {order3.name} creada para {order3.partner_id.name}")
    
    # Orden 4: Control pediátrico
    if len(patients) > 3:
        order4 = env['sale.order'].create({
            'partner_id': patients[3].id,
            'doctor_id': doctors[-1].id if doctors else False,
            'is_lab_request': True,
            # 'lab_request_priority': 'normal',  # Campo no existe aún
            'note': 'Control pediátrico - Evaluación de anemia, niña con palidez',
            'order_line': [
                (0, 0, {
                    'product_id': analyses[0].product_variant_id.id,  # Hemograma completo
                    'product_uom_qty': 1
                })
            ]
        })
        order4.action_confirm()
        orders_created.append(order4)
        print(f"✓ Orden pediátrica {order4.name} creada para {order4.partner_id.name}")
    
    print(f"\n📋 Total de órdenes creadas: {len(orders_created)}")
    
    # Procesar muestras y generar resultados
    for idx, order in enumerate(orders_created):
        print(f"\n--- Procesando orden {idx + 1}/{len(orders_created)}: {order.name} ---")
        
        # Generar muestras si no existen
        if not order.generated_sample_ids:
            order.action_generate_samples()
            print(f"  ✓ Muestras generadas: {len(order.generated_sample_ids)}")
        
        # Procesar cada muestra
        for sample in order.generated_sample_ids:
            # Marcar como recolectada
            if sample.sample_state == 'pending_collection':
                sample.action_collect()
                print(f"  ✓ Muestra {sample.name} recolectada")
            
            # Procesar pruebas de esta muestra
            for test in sample.test_ids:
                print(f"    - Procesando prueba: {test.product_id.name}")
                
                # Iniciar proceso si está en borrador
                if test.state == 'draft':
                    test.action_start_process()
                
                # La generación automática de resultados ya debería haberse ejecutado
                if test.result_ids:
                    print(f"      ✓ Resultados generados automáticamente: {len(test.result_ids)}")
                    
                    # Simular ingreso de valores en los resultados
                    simulate_test_results(env, test)
                    
                    # Marcar como resultados ingresados
                    if test.state == 'in_process':
                        test.action_enter_results()
                        print(f"      ✓ Resultados ingresados")
                    
                    # Validar las primeras 2 órdenes completas y algunas pruebas de la tercera
                    should_validate = (idx < 2) or (idx == 2 and test == sample.test_ids[0])
                    
                    if should_validate and test.state == 'result_entered':
                        test.action_validate()
                        print(f"      ✓ Prueba validada")
                else:
                    print(f"      ⚠️  No se generaron resultados automáticamente")
    
    # Resumen final
    print("\n" + "="*60)
    print("RESUMEN DE DATOS CREADOS")
    print("="*60)
    
    # Contar registros creados
    total_samples = env['stock.lot'].search_count([('is_lab_sample', '=', True)])
    total_tests = env['lims.test'].search_count([])
    total_results = env['lims.result'].search_count([])
    
    tests_by_state = {}
    for state in ['draft', 'in_process', 'result_entered', 'validated', 'cancelled']:
        count = env['lims.test'].search_count([('state', '=', state)])
        if count > 0:
            tests_by_state[state] = count
    
    print(f"\n📊 Estadísticas:")
    print(f"  - Órdenes de laboratorio: {len(orders_created)}")
    print(f"  - Muestras totales: {total_samples}")
    print(f"  - Pruebas totales: {total_tests}")
    print(f"  - Resultados totales: {total_results}")
    print(f"\n📈 Pruebas por estado:")
    for state, count in tests_by_state.items():
        print(f"  - {state}: {count}")
    
    # Verificar algunos resultados fuera de rango
    out_of_range = env['lims.result'].search_count([('is_out_of_range', '=', True)])
    critical = env['lims.result'].search_count([('is_critical', '=', True)])
    
    if out_of_range or critical:
        print(f"\n⚠️  Valores anormales:")
        print(f"  - Fuera de rango: {out_of_range}")
        print(f"  - Críticos: {critical}")
    
    print("\n✅ Datos de demostración creados exitosamente")


def simulate_test_results(env, test):
    """Simular el ingreso de resultados realistas para una prueba"""
    
    for result in test.result_ids:
        param = result.parameter_id
        
        if param.value_type == 'numeric':
            # Generar valor numérico considerando el rango normal
            if result.applicable_range_id:
                range_obj = result.applicable_range_id
                
                # Probabilidades: 75% normal, 20% anormal, 5% crítico
                rand = random.random()
                
                if rand < 0.75:  # Valor normal
                    # Generar valor dentro del rango normal
                    value = random.uniform(range_obj.normal_min, range_obj.normal_max)
                    
                elif rand < 0.95:  # Valor anormal pero no crítico
                    # Decidir si va por arriba o por abajo
                    if random.random() < 0.5 and range_obj.normal_min > 0:
                        # Por debajo del normal
                        value = random.uniform(range_obj.normal_min * 0.7, range_obj.normal_min * 0.95)
                    else:
                        # Por encima del normal
                        value = random.uniform(range_obj.normal_max * 1.05, range_obj.normal_max * 1.3)
                        
                else:  # Valor crítico (5%)
                    if range_obj.critical_min and random.random() < 0.5:
                        # Crítico bajo
                        value = random.uniform(range_obj.critical_min * 0.5, range_obj.critical_min * 0.9)
                    elif range_obj.critical_max:
                        # Crítico alto
                        value = random.uniform(range_obj.critical_max * 1.1, range_obj.critical_max * 1.5)
                    else:
                        # Si no hay valores críticos definidos, usar un valor muy anormal
                        value = range_obj.normal_max * 2.0
                
                # Redondear según el tipo de parámetro
                if param.code in ['HGB', 'CREA', 'GLU', 'CHOL', 'HDL', 'LDL', 'TRIG']:
                    result.value_numeric = round(value, 1)
                elif param.code in ['U-PH', 'U-DENS']:
                    result.value_numeric = round(value, 3)
                else:
                    result.value_numeric = round(value, 2)
                    
                # Agregar notas para valores anormales en algunos casos
                if result.is_out_of_range and random.random() < 0.3:
                    if param.code == 'GLU' and result.value_numeric > 126:
                        result.notes = "Hiperglucemia - Sugerir control de diabetes"
                    elif param.code == 'WBC' and result.value_numeric > 11:
                        result.notes = "Leucocitosis - Posible proceso infeccioso"
                    elif param.code == 'HGB' and result.value_numeric < range_obj.normal_min:
                        result.notes = "Anemia - Evaluar causa"
                        
            else:
                # Sin rango definido, usar valores típicos
                result.value_numeric = round(random.uniform(10, 100), 2)
                
        elif param.value_type == 'selection':
            # Seleccionar una opción con pesos realistas
            if param.selection_values:
                options = [opt.strip() for opt in param.selection_values.split(',')]
                
                # Para cultivos, 70% negativo, 30% positivo
                if param.code in ['CULT', 'HIV', 'HBsAg', 'HCV', 'VDRL']:
                    if 'Negativo' in options or 'No Reactivo' in options:
                        negative_option = 'Negativo' if 'Negativo' in options else 'No Reactivo'
                        positive_option = 'Positivo' if 'Positivo' in options else 'Reactivo'
                        result.value_selection = negative_option if random.random() < 0.7 else positive_option
                    else:
                        result.value_selection = random.choice(options)
                        
                # Para orina, distribución más realista
                elif param.code == 'U-COLOR':
                    weights = [0.1, 0.6, 0.2, 0.05, 0.02, 0.02, 0.01]  # Amarillo más común
                    result.value_selection = random.choices(options, weights=weights[:len(options)])[0]
                    
                elif param.code == 'U-ASP':
                    weights = [0.7, 0.2, 0.08, 0.02]  # Transparente más común
                    result.value_selection = random.choices(options, weights=weights[:len(options)])[0]
                    
                else:
                    # Primera opción más probable (generalmente es la normal)
                    weights = [0.7] + [0.3/(len(options)-1)]*(len(options)-1)
                    result.value_selection = random.choices(options, weights=weights)[0]
                    
        elif param.value_type == 'boolean':
            # Para pruebas de embarazo, considerar el género del paciente
            if param.code == 'HCG' and test.patient_id.gender == 'female' and test.patient_id.is_pregnant:
                result.value_boolean = True
            else:
                # 85% probabilidad de False (negativo) para la mayoría de pruebas
                result.value_boolean = random.random() > 0.85
                
        elif param.value_type == 'text':
            # Generar texto según el parámetro
            if param.code == 'MICRO':
                # Solo si el cultivo es positivo
                culture_result = test.result_ids.filtered(
                    lambda r: r.parameter_id.code == 'CULT'
                )
                if culture_result and culture_result.value_selection == 'Positivo':
                    organisms = ['E. coli', 'Klebsiella pneumoniae', 'Proteus mirabilis', 
                               'Enterococcus faecalis', 'Staphylococcus aureus', 
                               'Pseudomonas aeruginosa', 'Streptococcus agalactiae']
                    result.value_text = random.choice(organisms)
                else:
                    result.value_text = "No se aisló microorganismo"
                    
            elif param.code == 'UFC':
                # Solo si hay microorganismo
                micro_result = test.result_ids.filtered(
                    lambda r: r.parameter_id.code == 'MICRO'
                )
                if micro_result and micro_result.value_text and micro_result.value_text != "No se aisló microorganismo":
                    counts = ['>100,000', '>50,000', '>10,000', '<10,000']
                    weights = [0.5, 0.3, 0.15, 0.05]
                    result.value_text = random.choices(counts, weights=weights)[0] + " UFC/mL"


if __name__ == '__main__':
    db_name = 'lims_demo'
    registry = odoo.registry(db_name)
    with registry.cursor() as cr:
        create_demo_lab_data(cr)
        cr.commit()