"""
BIOS Baseline 관리 라우트
backend/routes/bios_baseline_routes.py

BIOS Baseline 생성, 조회, 수정, 삭제 및 비교 기능 제공
"""

from flask import Blueprint, render_template, request, jsonify, current_app
from backend.models.user import db
from backend.models.bios_baseline import BiosBaseline
from backend.services.idrac_redfish_client import DellRedfishClient
from datetime import datetime
import json
from sqlalchemy import text

# 비교 제외 대상 키 (서버별 고유값 등)
IGNORED_KEYS = {
    'BIOS': {
        'ServiceTag', 'AssetTag', 'SerialNumber', 'SystemServiceTag', 'SystemAssetTag', 'SystemSerialNumber'
    },
    'iDRAC': {
        'SystemID', 'DNSDomainName', 'DNSRacName', 'DNSDomainNameFromDHCP', 
        'IPv4.1.Address', 'IPv4.1.Gateway', 'IPv4.1.Netmask',
        'IPv4Static.1.Address', 'IPv4Static.1.Gateway', 'IPv4Static.1.Netmask',
        'IPv6.1.Address', 'IPv6.1.Gateway',
        'MACAddress', 'PermanentMACAddress'
    }
}

def compare_dictionaries(expected, actual, section_name, diff_list, metadata=None):
    """딕셔너리 비교 헬퍼 함수"""
    if not expected:
        return 0, 0
        
    matched = 0
    mismatched = 0
    
    ignored = IGNORED_KEYS.get(section_name, set())
    
    for key, exp_val in expected.items():
        if key in ignored:
            continue
            
        act_val = actual.get(key)
        # 문자열로 변환하여 비교 (타입 불일치 방지)
        if str(act_val) == str(exp_val):
            matched += 1
            # 일치하는 항목도 결과에 포함
            diff_item = {
                'section': section_name,
                'setting_name': key,
                'expected': exp_val,
                'actual': act_val,
                'status': 'match'
            }
            if metadata and key in metadata:
                diff_item['display_name'] = metadata[key]
            diff_list.append(diff_item)
        else:
            mismatched += 1
            
            diff_item = {
                'section': section_name,
                'setting_name': key,
                'expected': exp_val,
                'actual': act_val,
                'status': 'mismatch'
            }
            
            # Display Name 추가
            if metadata and key in metadata:
                diff_item['display_name'] = metadata[key]
                
            diff_list.append(diff_item)
    return matched, mismatched

def compare_raid_config(expected, actual, diff_list):
    """RAID 구성 비교"""
    if not expected or 'Controllers' not in expected:
        return 0, 0
    
    matched = 0
    mismatched = 0
    total_checks = 0
    
    # 컨트롤러별 비교
    exp_ctrls = {c.get('Name'): c for c in expected.get('Controllers', [])}
    act_ctrls = {c.get('Name'): c for c in actual.get('Controllers', [])}
    
    for name, exp_c in exp_ctrls.items():
        act_c = act_ctrls.get(name)
        
        if not act_c:
            mismatched += 1
            diff_list.append({
                'section': 'RAID',
                'setting_name': f"Controller [{name}]",
                'expected': "Present",
                'actual': "Missing",
                'status': 'mismatch'
            })
            continue
            
        matched += 1 # 컨트롤러 존재함
        diff_list.append({
            'section': 'RAID',
            'setting_name': f"Controller [{name}]",
            'expected': "Present",
            'actual': "Present",
            'status': 'match'
        })
        
        # 펌웨어 버전 비교
        exp_fw = exp_c.get('FirmwareVersion')
        act_fw = act_c.get('FirmwareVersion')
        if exp_fw and (exp_fw == act_fw):
            matched += 1
            diff_list.append({
                'section': 'RAID',
                'setting_name': f"Controller [{name}] Firmware",
                'expected': exp_fw,
                'actual': act_fw,
                'status': 'match'
            })
        else:
            mismatched += 1
            diff_list.append({
                'section': 'RAID',
                'setting_name': f"Controller [{name}] Firmware",
                'expected': exp_fw,
                'actual': act_fw,
                'status': 'mismatch'
            })
            
        # Volumes (Virtual Disks) 비교
        exp_vols = {v.get('Name'): v for v in exp_c.get('Volumes', [])}
        act_vols = {v.get('Name'): v for v in act_c.get('Volumes', [])}
        
        # Volume 개수 확인
        if len(exp_vols) != len(act_vols):
             diff_list.append({
                'section': 'RAID',
                'setting_name': f"Controller [{name}] Volume Count",
                'expected': len(exp_vols),
                'actual': len(act_vols),
                'status': 'warning'
            })
            
        for vname, exp_v in exp_vols.items():
            act_v = act_vols.get(vname)
            if not act_v:
                mismatched += 1
                diff_list.append({
                    'section': 'RAID',
                    'setting_name': f"Volume [{name}/{vname}]",
                    'expected': "Present",
                    'actual': "Missing",
                    'status': 'mismatch'
                })
                continue
                
            # RAID Level 비교
            if exp_v.get('RaidType') == act_v.get('RaidType'):
                matched += 1
                diff_list.append({
                    'section': 'RAID',
                    'setting_name': f"Volume [{name}/{vname}] RAID Level",
                    'expected': exp_v.get('RaidType'),
                    'actual': act_v.get('RaidType'),
                    'status': 'match'
                })
            else:
                mismatched += 1
                diff_list.append({
                    'section': 'RAID',
                    'setting_name': f"Volume [{name}/{vname}] RAID Level",
                    'expected': exp_v.get('RaidType'),
                    'actual': act_v.get('RaidType'),
                    'status': 'mismatch'
                })
                
            # 용량 비교 (오차 허용 없이)
            if exp_v.get('CapacityBytes') == act_v.get('CapacityBytes'):
                matched += 1
                diff_list.append({
                    'section': 'RAID',
                    'setting_name': f"Volume [{name}/{vname}] Capacity",
                    'expected': f"{exp_v.get('CapacityBytes', 0) / (1024**3):.2f} GB",
                    'actual': f"{act_v.get('CapacityBytes', 0) / (1024**3):.2f} GB",
                    'status': 'match'
                })
            else:
                mismatched += 1
                diff_list.append({
                    'section': 'RAID',
                    'setting_name': f"Volume [{name}/{vname}] Capacity",
                    'expected': f"{exp_v.get('CapacityBytes', 0) / (1024**3):.2f} GB",
                    'actual': f"{act_v.get('CapacityBytes', 0) / (1024**3):.2f} GB",
                    'status': 'mismatch'
                })

    return matched, mismatched

bios_baseline_bp = Blueprint('bios_baseline', __name__, url_prefix='/bios-baseline')

# ========================================
# 페이지 라우트
# ========================================

@bios_baseline_bp.route('/')
def index():
    """BIOS Baseline 비교 메인 페이지"""
    return render_template('bios_baseline.html')

# ========================================
# Baseline 관리 API
# ========================================

@bios_baseline_bp.route('/api/baselines', methods=['GET'])
def get_baselines():
    """
    등록된 baseline 목록 조회
    Query params:
    - server_model: 특정 모델 필터링
    - server_type: 특정 타입 필터링
    - include_data: true면 bios_data도 포함
    """
    try:
        server_model = request.args.get('server_model')
        server_type = request.args.get('server_type')
        include_data = request.args.get('include_data', 'false').lower() == 'true'
        
        query = BiosBaseline.query.filter_by(is_active=True)
        
        if server_model:
            query = query.filter_by(server_model=server_model)
        if server_type:
            query = query.filter_by(server_type=server_type)
        
        baselines = query.order_by(BiosBaseline.created_at.desc()).all()
        
        return jsonify({
            'success': True,
            'baselines': [b.to_dict(include_data=include_data) for b in baselines]
        })
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})

@bios_baseline_bp.route('/api/baselines/<int:baseline_id>', methods=['GET'])
def get_baseline(baseline_id):
    """특정 baseline 상세 조회 (bios_data 포함)"""
    try:
        baseline = BiosBaseline.query.get(baseline_id)
        if not baseline:
            return jsonify({'success': False, 'message': 'Baseline을 찾을 수 없습니다'})
        
        return jsonify({
            'success': True,
            'baseline': baseline.to_dict(include_data=True)
        })
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})

def compare_nic_config(baseline_nic, target_nic, diff_list):
    """NIC 구성 비교 (ID 기준 매칭)"""
    matched = 0
    mismatched = 0

    if not baseline_nic and not target_nic:
        return 0, 0
    if not baseline_nic:
        diff_list.append({'section': 'NIC', 'setting_name': 'NIC Configuration', 'expected': 'Present', 'actual': 'Missing', 'status': 'mismatch'})
        return 0, 1
    if not target_nic:
        diff_list.append({'section': 'NIC', 'setting_name': 'NIC Configuration', 'expected': 'Missing', 'actual': 'Present', 'status': 'mismatch'})
        return 0, 1

    # Adapters 리스트를 ID 기준 딕셔너리로 변환
    def to_dict_by_id(adapters):
        return {a.get('Id', 'Unknown'): a for a in adapters.get('Adapters', [])}
        
    base_map = to_dict_by_id(baseline_nic)
    target_map = to_dict_by_id(target_nic)
    
    all_ids = set(base_map.keys()) | set(target_map.keys())
    
    for aid in all_ids:
        b_adp = base_map.get(aid)
        t_adp = target_map.get(aid)
        
        if not b_adp:
            mismatched += 1
            diff_list.append({'section': 'NIC', 'setting_name': f"NIC [{aid}]", 'expected': 'None', 'actual': 'Added', 'status': 'mismatch'})
            continue
        if not t_adp:
            mismatched += 1
            diff_list.append({'section': 'NIC', 'setting_name': f"NIC [{aid}]", 'expected': 'Present', 'actual': 'Missing', 'status': 'mismatch'})
            continue
            
        matched += 1 # Adapter exists in both
        diff_list.append({'section': 'NIC', 'setting_name': f"NIC [{aid}]", 'expected': 'Present', 'actual': 'Present', 'status': 'match'})
        
        # 어댑터 속성 비교 (Firmware 등)
        for field in ['FirmwareVersion', 'Model']:
            bv = b_adp.get(field)
            tv = t_adp.get(field)
            if bv == tv:
                matched += 1
                diff_list.append({'section': 'NIC', 'setting_name': f"NIC [{aid}] {field}", 'expected': bv, 'actual': tv, 'status': 'match'})
            else:
                mismatched += 1
                diff_list.append({'section': 'NIC', 'setting_name': f"NIC [{aid}] {field}", 'expected': bv, 'actual': tv, 'status': 'mismatch'})
                
        # DeviceFunctions 비교
        b_funcs = {f.get('Id'): f for f in b_adp.get('DeviceFunctions', [])}
        t_funcs = {f.get('Id'): f for f in t_adp.get('DeviceFunctions', [])}
        
        for fid in set(b_funcs.keys()) | set(t_funcs.keys()):
            bf = b_funcs.get(fid)
            tf = t_funcs.get(fid)
            
            prefix = f"NIC [{aid}] Func [{fid}]"
            
            if not bf:
                 # Baseline에 없는데 Target에 있음 (일반적이지 않음, 설정 변경일 수 있음)
                 # This is an 'added' function, count as mismatch
                 mismatched += 1
                 diff_list.append({'section': 'NIC', 'setting_name': prefix, 'expected': 'None', 'actual': 'Added', 'status': 'mismatch'})
                 continue
            if not tf:
                 mismatched += 1
                 diff_list.append({'section': 'NIC', 'setting_name': prefix, 'expected': 'Present', 'actual': 'Missing', 'status': 'mismatch'})
                 continue
            
            matched += 1 # Function exists in both
            diff_list.append({'section': 'NIC', 'setting_name': prefix, 'expected': 'Present', 'actual': 'Present', 'status': 'match'})
                 
            # 속성 비교 (BootMode, iSCSI, Ethernet)
            if bf.get('NetBootPMMode') == tf.get('NetBootPMMode'):
                matched += 1
                diff_list.append({'section': 'NIC', 'setting_name': f"{prefix} BootMode", 'expected': bf.get('NetBootPMMode'), 'actual': tf.get('NetBootPMMode'), 'status': 'match'})
            else:
                mismatched += 1
                diff_list.append({'section': 'NIC', 'setting_name': f"{prefix} BootMode", 'expected': bf.get('NetBootPMMode'), 'actual': tf.get('NetBootPMMode'), 'status': 'mismatch'})
            
            # Add more specific NIC settings comparison here if needed
            # For example, comparing specific Ethernet or iSCSI settings
            # For now, we'll consider the presence and BootMode.

    return matched, mismatched

@bios_baseline_bp.route('/api/baselines/create-from-server', methods=['POST'])
def create_baseline_from_server():
    """
    Redfish로 서버에서 BIOS 설정을 가져와 새 baseline 생성
    Request: {
        "ip_address": "10.10.0.1",
        "username": "root",
        "password": "calvin",
        "name": "R6615_GPU_Standard_2024",
        "server_type": "GPU Server",
        "description": "표준 GPU 서버 설정",
        "created_by": "admin"
    }
    """
    try:
        data = request.json
        
        # 필수 필드 체크
        if not all(k in data for k in ['ip_address', 'username', 'password', 'name']):
            return jsonify({'success': False, 'message': '필수 필드 누락'})
        
        # 이름 중복 체크
        if BiosBaseline.query.filter_by(name=data['name'], is_active=True).first():
            return jsonify({'success': False, 'message': '이미 존재하는 Baseline 이름입니다'})
        
        # 1. Redfish로 BIOS 설정 가져오기
        client = DellRedfishClient(data['ip_address'], data['username'], data['password'])
        
        if not client.check_connection():
            return jsonify({'success': False, 'message': '서버 연결 실패'})
        
        # 2. 서버 정보 및 BIOS 설정 가져오기
        system_info = client.get_system_info_detailed()
        bios_data = client.get_bios_attributes_all()
        # BIOS Registry (Display Name) 가져오기
        bios_metadata = client.get_bios_attribute_registry()
        
        idrac_data = client.get_idrac_attributes_all()
        # iDRAC Registry (Display Name) 가져오기
        idrac_metadata = client.get_idrac_attribute_registry()
        
        raid_data = client.get_storage_configuration()
        nic_data = client.get_nic_configuration()
        boot_data = client.get_boot_settings()
        firmware_data = client.get_firmware_baseline()
        
        if not bios_data:
            return jsonify({'success': False, 'message': 'BIOS 설정 가져오기 실패'})
        
        # 3. Baseline 생성
        baseline = BiosBaseline(
            name=data['name'],
            server_model=system_info.get('Model', 'Unknown'),
            server_type=data.get('server_type'),
            description=data.get('description'),
            bios_data=bios_data,
            bios_metadata=bios_metadata, # 메타데이터 저장
            idrac_data=idrac_data,
            idrac_metadata=idrac_metadata, # iDRAC 메타데이터 저장
            raid_data=raid_data,
            nic_data=nic_data,
            boot_data=boot_data,
            firmware_data=firmware_data,
            source_ip=data['ip_address'],
            source_service_tag=system_info.get('ServiceTag'),
            bios_version=bios_data.get('BiosVersion'),
            total_settings=len(bios_data) + len(idrac_data) + len(raid_data.get('Controllers', [])) + len(nic_data.get('Adapters', [])) + len(boot_data.get('BootSources', [])) + len(firmware_data.get('FirmwareInventory', [])),
            created_by=data.get('created_by', 'admin')
        )
        
        db.session.add(baseline)
        db.session.commit()
        
        return jsonify({
            'success': True,
            'message': 'Baseline 생성 완료',
            'baseline': baseline.to_dict()
        })
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': f'오류: {str(e)}'})

@bios_baseline_bp.route('/api/baselines/<int:baseline_id>/duplicate', methods=['POST'])
def duplicate_baseline(baseline_id):
    """
    기존 baseline을 복사하여 새 baseline 생성
    Request: {
        "new_name": "R6615_GPU_ClientA",
        "description": "고객사 A 맞춤 설정"
    }
    """
    try:
        data = request.json
        original = BiosBaseline.query.get(baseline_id)
        
        if not original:
            return jsonify({'success': False, 'message': '원본 Baseline을 찾을 수 없습니다'})
        
        # 이름 중복 체크
        if BiosBaseline.query.filter_by(name=data['new_name'], is_active=True).first():
            return jsonify({'success': False, 'message': '이미 존재하는 Baseline 이름입니다'})
        
        # 복사 생성
        new_baseline = BiosBaseline(
            name=data['new_name'],
            server_model=original.server_model,
            server_type=original.server_type,
            description=data.get('description', f"{original.name}의 복사본"),
            bios_data=original.bios_data.copy() if original.bios_data else {},
            bios_metadata=original.bios_metadata.copy() if original.bios_metadata else {}, # 메타데이터 복사
            idrac_data=original.idrac_data.copy() if original.idrac_data else {},
            idrac_metadata=original.idrac_metadata.copy() if original.idrac_metadata else {}, # iDRAC 메타데이터 복사
            raid_data=original.raid_data.copy() if original.raid_data else {}, # JSON 복사
            nic_data=original.nic_data.copy() if original.nic_data else {},
            boot_data=original.boot_data.copy() if original.boot_data else {},
            firmware_data=original.firmware_data.copy() if original.firmware_data else {},
            source_ip=original.source_ip,
            source_service_tag=original.source_service_tag,
            bios_version=original.bios_version,
            total_settings=original.total_settings,
            copied_from_id=original.id,
            created_by=data.get('created_by', 'admin')
        )
        
        db.session.add(new_baseline)
        db.session.commit()
        
        return jsonify({
            'success': True,
            'message': 'Baseline 복사 완료',
            'baseline': new_baseline.to_dict()
        })
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': f'오류: {str(e)}'})

@bios_baseline_bp.route('/api/baselines/<int:baseline_id>', methods=['PUT'])
def update_baseline(baseline_id):
    """
    Baseline 수정 (메타데이터 및 bios_data)
    Request: {
        "name": "새 이름",
        "description": "새 설명",
        "bios_data": { ... }  // 선택사항
    }
    """
    try:
        baseline = BiosBaseline.query.get_or_404(baseline_id)
        data = request.json
        
        # 이름 변경 시 중복 체크
        if 'name' in data and data['name'] != baseline.name:
            if BiosBaseline.query.filter_by(name=data['name'], is_active=True).first():
                return jsonify({'success': False, 'message': '이미 존재하는 Baseline 이름입니다'})
            baseline.name = data['name']
        
        # 메타데이터 업데이트
        if 'description' in data:
            baseline.description = data['description']
        if 'server_type' in data:
            baseline.server_type = data['server_type']
        
        # BIOS 데이터 업데이트 (선택사항)
        if 'bios_data' in data:
            baseline.bios_data = data['bios_data']
        if 'bios_metadata' in data:
            baseline.bios_metadata = data['bios_metadata']
        if 'idrac_data' in data:
            baseline.idrac_data = data['idrac_data']
        if 'idrac_metadata' in data:
            baseline.idrac_metadata = data['idrac_metadata']
        if 'raid_data' in data:
            baseline.raid_data = data['raid_data']
        if 'nic_data' in data:
            baseline.nic_data = data['nic_data']
        if 'boot_data' in data:
            baseline.boot_data = data['boot_data']
        if 'firmware_data' in data:
            baseline.firmware_data = data['firmware_data']
            
        # 총 설정 수 재계산
        total = 0
        if baseline.bios_data: total += len(baseline.bios_data)
        if baseline.idrac_data: total += len(baseline.idrac_data)
        if baseline.raid_data and 'Controllers' in baseline.raid_data: total += len(baseline.raid_data['Controllers'])
        if baseline.nic_data and 'Adapters' in baseline.nic_data: total += len(baseline.nic_data['Adapters'])
        if baseline.boot_data and 'BootSources' in baseline.boot_data: total += len(baseline.boot_data['BootSources'])
        if baseline.firmware_data and 'FirmwareInventory' in baseline.firmware_data: total += len(baseline.firmware_data['FirmwareInventory'])
        baseline.total_settings = total
        
        baseline.updated_at = datetime.utcnow()
        db.session.commit()
        
        return jsonify({
            'success': True,
            'message': 'Baseline 수정 완료',
            'baseline': baseline.to_dict()
        })
        
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': f'오류: {str(e)}'})

@bios_baseline_bp.route('/api/baselines/<int:baseline_id>', methods=['DELETE'])
def delete_baseline(baseline_id):
    """Baseline 삭제 (Soft Delete)"""
    try:
        baseline = BiosBaseline.query.get(baseline_id)
        if not baseline:
            return jsonify({'success': False, 'message': 'Baseline을 찾을 수 없습니다'})
        
        baseline.is_active = False
        # 이름 충돌 방지를 위해 이름 변경 (Soft Delete 시)
        # 예: "MyServer" -> "MyServer_deleted_1678901234"
        baseline.name = f"{baseline.name}_deleted_{int(datetime.utcnow().timestamp())}"
        db.session.commit()
        
        return jsonify({'success': True, 'message': 'Baseline 삭제 완료'})
    except Exception as e:
        db.session.rollback()
        return jsonify({'success': False, 'message': str(e)})

# ========================================
# 비교 API
# ========================================

@bios_baseline_bp.route('/api/compare', methods=['POST'])
def compare_with_baseline():
    """
    IP 주소로 서버 BIOS 설정을 가져와 baseline과 비교
    Request: {
        "ip_addresses": ["10.10.0.1", "10.10.0.2"],
        "baseline_id": 1,
        "username": "root",
        "password": "calvin"
    }
    """
    try:
        data = request.json
        baseline = BiosBaseline.query.get(data['baseline_id'])
        
        if not baseline:
            return jsonify({'success': False, 'message': 'Baseline을 찾을 수 없습니다'})
        
        results = []
        
        # 병렬 처리를 위한 함수 정의
        def process_server(ip):
            try:
                # 1. Redfish로 현재 BIOS 설정 가져오기
                client = DellRedfishClient(ip, data['username'], data['password'])
                
                if not client.check_connection():
                    return {
                        'ip': ip,
                        'status': 'connection_failed',
                        'message': '서버 연결 실패'
                    }
                
                # 2. Redfish로 현재 설정 가져오기
                system_info = client.get_system_info_detailed()
                current_bios = client.get_bios_attributes_all()
                current_idrac = client.get_idrac_attributes_all()
                current_raid = client.get_storage_configuration()
                current_nic = client.get_nic_configuration()
                current_boot = client.get_boot_settings()
                current_firmware = client.get_firmware_baseline()
                
                if not current_bios:
                    return {
                        'ip': ip,
                        'status': 'error',
                        'message': 'BIOS 설정 가져오기 실패'
                    }
                
                # 3. Baseline과 비교
                differences = []
                total_matched = 0
                total_mismatched = 0
                
                # 3-1. BIOS 비교
                b_matched, b_mismatched = compare_dictionaries(baseline.bios_data, current_bios, 'BIOS', differences, baseline.bios_metadata)
                total_matched += b_matched
                total_mismatched += b_mismatched
                
                # 3-2. iDRAC 비교
                if baseline.idrac_data:
                    i_matched, i_mismatched = compare_dictionaries(baseline.idrac_data, current_idrac, 'iDRAC', differences, baseline.idrac_metadata)
                    total_matched += i_matched
                    total_mismatched += i_mismatched
                
                # 3-3. RAID 비교
                if baseline.raid_data:
                    r_matched, r_mismatched = compare_raid_config(baseline.raid_data, current_raid, differences)
                    total_matched += r_matched
                    total_mismatched += r_mismatched

                # 3-4. NIC 비교
                if baseline.nic_data:
                    n_matched, n_mismatched = compare_nic_config(baseline.nic_data, current_nic, differences)
                    total_matched += n_matched
                    total_mismatched += n_mismatched

                # 3-5. Boot 비교
                if baseline.boot_data:
                    boot_matched, boot_mismatched = compare_dictionaries(baseline.boot_data, current_boot, 'Boot', differences)
                    total_matched += boot_matched
                    total_mismatched += boot_mismatched

                # 3-6. Firmware 비교
                if baseline.firmware_data:
                    fw_matched, fw_mismatched = compare_dictionaries(baseline.firmware_data, current_firmware, 'Firmware', differences)
                    total_matched += fw_matched
                    total_mismatched += fw_mismatched
                
                # 4. 결과 저장
                match_rate = round((total_matched / (total_matched + total_mismatched)) * 100, 2) if (total_matched + total_mismatched) > 0 else 0
                
                return {
                    'ip': ip,
                    'status': 'success',
                    'server_model': system_info.get('Model'),
                    'service_tag': system_info.get('ServiceTag'),
                    'bios_version': current_bios.get('BiosVersion'), # Corrected from system_info.get('BiosVersion')
                    'total_items': total_matched + total_mismatched,
                    'matched_items': total_matched,
                    'mismatched_items': total_mismatched,
                    'match_rate': match_rate,
                    'differences': differences
                }
            except Exception as e:
                import traceback
                traceback.print_exc() # Keep traceback for debugging in logs
                return {
                    'ip': ip,
                    'status': 'error',
                    'message': str(e)
                }

        import concurrent.futures
        results = []
        max_workers = min(len(data['ip_addresses']), 20)  # 최대 20개 동시 실행
        
        with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
            future_to_ip = {executor.submit(process_server, ip): ip for ip in data['ip_addresses']}
            for future in concurrent.futures.as_completed(future_to_ip):
                ip = future_to_ip[future]
                try:
                    result = future.result()
                    results.append(result)
                except Exception as e:
                    results.append({
                        'ip': ip,
                        'status': 'error',
                        'message': f"예상치 못한 오류: {str(e)}"
                    })
        
        return jsonify({
            'success': True,
            'baseline': baseline.to_dict(),
            'results': results
        })
        
    except Exception as e:
        return jsonify({'success': False, 'message': f'오류: {str(e)}'})

# ========================================
# Blueprint 등록 함수
# ========================================

def register_bios_baseline_routes(app):
    """
    bios_baseline_routes 등록 및 초기화
    """
    app.register_blueprint(bios_baseline_bp)
    
    # CSRF 제외
    try:
        csrf = app.extensions.get('csrf')
        if csrf:
            csrf.exempt(bios_baseline_bp)
    except Exception as e:
        app.logger.warning(f"CSRF exemption failed for bios_baseline_bp: {e}")
    
    # DB 마이그레이션: 필요한 컬럼이 없으면 추가
    # SQLite 등에서 ALTER TABLE은 제한적일 수 있으나 여기서는 단순 컬럼 추가 시도
    with app.app_context():
        inspector = db.inspect(db.engine)
        
        # Ensure table exists before checking columns
        db.create_all() 

        columns = [c['name'] for c in inspector.get_columns('bios_baselines')]
        
        if 'idrac_data' not in columns:
            print("[INFO] Migrating BIOS Baseline table: Adding idrac_data")
            with db.engine.connect() as conn:
                conn.execute(text("ALTER TABLE bios_baselines ADD COLUMN idrac_data JSON"))
                conn.commit()

        if 'bios_metadata' not in columns:
            print("[INFO] Migrating BIOS Baseline table: Adding bios_metadata")
            with db.engine.connect() as conn:
                conn.execute(text("ALTER TABLE bios_baselines ADD COLUMN bios_metadata JSON"))
                conn.commit()

        if 'idrac_metadata' not in columns:
            print("[INFO] Migrating BIOS Baseline table: Adding idrac_metadata")
            with db.engine.connect() as conn:
                conn.execute(text("ALTER TABLE bios_baselines ADD COLUMN idrac_metadata JSON"))
                conn.commit()
                
        if 'raid_data' not in columns:
            print("[INFO] Migrating BIOS Baseline table: Adding raid_data")
            with db.engine.connect() as conn:
                conn.execute(text("ALTER TABLE bios_baselines ADD COLUMN raid_data JSON"))
                conn.commit()

        if 'nic_data' not in columns:
            print("[INFO] Migrating BIOS Baseline table: Adding nic_data")
            with db.engine.connect() as conn:
                conn.execute(text("ALTER TABLE bios_baselines ADD COLUMN nic_data JSON"))
                conn.commit()

        if 'boot_data' not in columns:
            print("[INFO] Migrating BIOS Baseline table: Adding boot_data")
            with db.engine.connect() as conn:
                conn.execute(text("ALTER TABLE bios_baselines ADD COLUMN boot_data JSON"))
                conn.commit()

        if 'firmware_data' not in columns:
            print("[INFO] Migrating BIOS Baseline table: Adding firmware_data")
            with db.engine.connect() as conn:
                conn.execute(text("ALTER TABLE bios_baselines ADD COLUMN firmware_data JSON"))
                conn.commit()

