package com.sensor.bridge;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * BME680 환경 센서 파서
 * 온도, 기압, 습도, 가스 센서 (정확도: ±0.5°C)
 */
public class BME680Parser implements SensorParser {
    
    private static final Logger logger = LoggerFactory.getLogger(BME680Parser.class);
    private static final String SENSOR_TYPE = "BME680";
    
    // BME680 센서 특성
    private static final double TEMPERATURE_ACCURACY = 0.5; // ±0.5°C
    private static final double TEMPERATURE_RESOLUTION = 0.01; // 0.01°C
    
    @Override
    public double parseTemperature(SensorData data, ParamItem paramItem) {
        logger.debug("BME680 온도 파싱 시작: rawTem={}, floatValue={}, signedInt32Value={}", 
                    data.getRawTem(), data.getFloatValue(), data.getSignedInt32Value());
        
        // 1. param.dat 기반 보정 적용
        if (paramItem != null && paramItem.getScaleFactor() != 1.0) {
            double calibratedTemp = paramItem.calculateCalibratedTemperature(data.getRawTem());
            if (paramItem.isValidTemperature(calibratedTemp)) {
                logger.debug("BME680 param.dat 기반 보정 적용: {} -> {}°C", data.getRawTem(), calibratedTemp);
                return calibratedTemp;
            }
        }
        
        // 2. BME680 특화 파싱 로직
        // BME680은 보통 floatValue에 직접 온도값을 저장
        if (data.getFloatValue() >= -40.0 && data.getFloatValue() <= 80.0) {
            logger.debug("BME680 floatValue 사용: {}°C", data.getFloatValue());
            return data.getFloatValue();
        }
        
        // 3. signedInt32Value에서 온도 추출 (BME680 특화)
        if (data.getSignedInt32Value() != 0) {
            double temp = extractTemperatureFromInt32(data.getSignedInt32Value());
            if (isValidTemperature(temp)) {
                logger.debug("BME680 signedInt32Value에서 추출: {} -> {}°C", data.getSignedInt32Value(), temp);
                return temp;
            }
        }
        
        // 4. rawTem 기반 파싱 (백업)
        if (data.getRawTem() >= 0 && data.getRawTem() <= 50) {
            double temperature = data.getRawTem() * 10;
            if (isValidTemperature(temperature)) {
                logger.debug("BME680 rawTem 기반 파싱: {} -> {}°C", data.getRawTem(), temperature);
                return temperature;
            }
        }
        
        // 5. 기본값 반환
        logger.warn("BME680: 모든 파싱 방법 실패, 기본값 사용");
        return paramItem != null ? paramItem.getDefaultValue() : 25.0;
    }
    
    @Override
    public boolean isValid(SensorData data) {
        // BME680 센서 데이터 유효성 검증
        return data != null && 
               (data.getFloatValue() >= -40.0 || 
                data.getSignedInt32Value() != 0 || 
                data.getRawTem() >= 0);
    }
    
    @Override
    public String getSensorType() {
        return SENSOR_TYPE;
    }
    
    @Override
    public double getParsingQuality(SensorData data) {
        if (!isValid(data)) {
            return 0.0;
        }
        
        // 파싱 품질 점수 계산 (0.0 ~ 1.0)
        double quality = 0.0;
        
        // floatValue 기반 파싱 가능성 (BME680 우선)
        if (data.getFloatValue() >= -40.0 && data.getFloatValue() <= 80.0) {
            quality += 0.5;
        }
        
        // signedInt32Value 기반 파싱 가능성
        if (data.getSignedInt32Value() != 0) {
            quality += 0.3;
        }
        
        // rawTem 기반 파싱 가능성
        if (data.getRawTem() >= 0 && data.getRawTem() <= 50) {
            quality += 0.2;
        }
        
        return Math.min(quality, 1.0);
    }
    
    private double extractTemperatureFromInt32(int signedInt32Value) {
        // BME680 특화 온도 추출 로직
        
        // 패턴 1: 대시보드 매칭
        if (signedInt32Value > 500000 && signedInt32Value < 600000) {
            return signedInt32Value / 18000.0;
        }
        
        // 패턴 2: 0.1도 단위 저장
        if (signedInt32Value > 0 && signedInt32Value < 5000) {
            return signedInt32Value / 10.0;
        }
        
        // 패턴 3: 직접 온도값
        if (signedInt32Value >= -400 && signedInt32Value <= 800) {
            return signedInt32Value / 10.0;
        }
        
        // 다른 스케일 팩터 시도
        double[] scaleFactors = {0.1, 0.01, 1.0, 10.0, 100.0};
        for (double scale : scaleFactors) {
            double temp = signedInt32Value * scale;
            if (isValidTemperature(temp)) {
                return temp;
            }
        }
        
        return 25.0; // 기본값
    }
    
    private boolean isValidTemperature(double temperature) {
        return temperature >= -40.0 && temperature <= 80.0;
    }
}
