package quant.rich.emoney.entity.config;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.fasterxml.jackson.annotation.JsonView;

import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.interfaces.ConfigInfo;
import quant.rich.emoney.interfaces.IConfig;

@Data
@Accessors(chain = true)
@Slf4j
@ConfigInfo(
    field = "deviceInfo",
    name = "设备信息设置",
    initDefault = true,
    managed = false)
public class DeviceInfoConfig implements IConfig<DeviceInfoConfig> {

    
    private static final Random RANDOM = new Random();
    
    @JsonView(IConfig.Views.Persistence.class)
    List<DeviceInfo> deviceInfos;
    
    public DeviceInfoConfig() {
        deviceInfos = new ArrayList<>();
    }
    
    /**
     * 获取随机设备信息
     * @return
     */
    public DeviceInfo getRandomDeviceInfo() {
        if (deviceInfos.isEmpty()) return null;
        return deviceInfos.get(RANDOM.nextInt(deviceInfos.size()));
    }

    @Data
    @Accessors(chain=true)
    @Slf4j
    public static class DeviceInfo {
        
        // 持久化在本地的 DeviceInfo 只有三个字段：
        // model、deviceType 和 fingerprint
        // 其中除 model 和 deviceType 外，其他字段全部从 fingerprint 派生
        // 也就是说只要提供 model、deviceType 和 fingerprint 就能创建一个 DeviceInfo 实例
        
        @JsonView(IConfig.Views.Persistence.class)
        private String model;
        private String brand;
        private String product;
        private String device;
        @JsonView(IConfig.Views.Persistence.class)
        private String deviceType;
        private String versionRelease;
        private String buildId;
        private String buildNumber;
        private String buildType;
        private String buildTags;
        
        /**
         * 用以匹配 fingerprint 的正则表达式
         */
        public static final Pattern PATTERN = Pattern.compile("^(?<brand>.*?)/(?<product>.*?)/(?<device>.*?):(?<versionRelease>.*?)/(?<buildId>.*?)/(?<buildNumber>.*?):(?<buildType>.*?)/(?<buildTags>.*?)$");

        private DeviceInfo() {}
        
        public DeviceInfo setFingerprint(String fingerprint) {
            Matcher m = PATTERN.matcher(fingerprint);
            if (!m.matches()) {
                throw new IllegalArgumentException("Fingerprint not match the pattern: " + fingerprint);
            }
            this.setBrand(m.group("brand"));
            this.setBuildId(m.group("buildId"));
            this.setBuildNumber(m.group("buildNumber"));
            this.setBuildTags(m.group("buildTags"));
            this.setBuildType(m.group("buildType"));
            this.setProduct(m.group("product"));
            this.setVersionRelease(m.group("versionRelease"));
            this.setDevice(m.group("device"));
            return this;
        }
        
        public DeviceInfo setDeviceType(String deviceType) {
            if (!"Mobile".equals(deviceType) && !"Pad".equals(deviceType)) {
                throw new IllegalArgumentException("DeviceType must be \"Mobile\" or \"Pad\", but got \"" + deviceType + "\"");
            }
            this.deviceType = deviceType;
            return this;
        }
        
        /**
         * 根据指定 model、fingerprint 和 deviceType 返回 DeviceInfo
         * @param model
         * @param fingerprint
         * @param deviceType
         * @return
         */
        public static DeviceInfo from(String model, String fingerprint, String deviceType) {
            
            DeviceInfo deviceInfo = new DeviceInfo();
            deviceInfo.setModel(model);
            deviceInfo.setFingerprint(fingerprint);
            deviceInfo.setDeviceType(deviceType);
            
            return deviceInfo;
        }
        
        public static DeviceInfo from(String model, String fingerprint) {
            return from(model, fingerprint, "Mobile");
        }
        
        /**
         * 从设备信息中还原 fingerprint
         * @return
         */
        @JsonView(IConfig.Views.Persistence.class)
        public String getFingerprint() {
            return String.format("%s/%s/%s:%s/%s/%s:%s/%s",
                getBrand(), getProduct(), getDevice(), getVersionRelease(),
                getBuildId(), getBuildNumber(), getBuildType(), getBuildTags()
            );
        }
        
        public final String toString() {
            return String.format("Model: %s, DeviceType: %s, Fingerprint: %s", 
                getModel(), getDeviceType(), getFingerprint()
            );
        }
        
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            DeviceInfo other = (DeviceInfo)obj;
            return hashCode() == other.hashCode();
        }
        
        public int hashCode() {
            return Objects.hash(getModel(), getDeviceType(), getFingerprint());
        }
    }
}
