package com.thinkunion.park.service.common.iot.capability.devicemodel;

import com.google.gson.JsonElement;
import com.thinkunion.park.service.common.iot.capability.devicemodel.rules.ArrayRule;
import com.thinkunion.park.service.common.iot.capability.devicemodel.rules.EnumRule;
import com.thinkunion.park.service.common.iot.capability.devicemodel.rules.MetaRule;
import com.thinkunion.park.service.common.iot.constant.ParamDataType;
import com.thinkunion.park.service.common.iot.exception.ApiRuntimeException;
import com.thinkunion.park.service.common.iot.exception.DataErrorException;
import com.thinkunion.park.service.common.iot.util.GsonUtils;
import com.thinkunion.park.service.common.iot.util.TextUtils;
import org.apache.commons.lang3.StringUtils;
import org.nest.springwrap.core.tool.api.DeviceCode;

import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

public class DeviceModel {

    private String id;
    private Profile profile;
    private List<Property> properties;
    private List<Event> events;
    private List<Service> services;

    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Profile getProfile() {
        return this.profile;
    }

    public void setProfile(Profile profile) {
        this.profile = profile;
    }

    public List<Property> getProperties() {
        return this.properties;
    }

    public void setProperties(List<Property> properties) {
        this.properties = properties;
    }

    public List<Event> getEvents() {
        return this.events;
    }

    public void setEvents(List<Event> events) {
        this.events = events;
    }

    public List<Service> getServices() {
        return this.services;
    }

    public void setServices(List<Service> services) {
        this.services = services;
    }

    public Service getServiceForAction(String action) {
        if (services.isEmpty()) {
            return null;
        }
        for (Service service : services) {
            if (service.getAction().equals(action)) {
                return service;
            }
        }
        return null;
    }

    public Event getEventForAction(String action) {
        if (events.isEmpty()) {
            return null;
        }
        for (Event event : events) {
            if (event.getAction().equals(action)) {
                return event;
            }
        }
        return null;
    }

    public Object getPropertyValue(String identify, String valueString) {
        Property property = getProp(identify);
        if (property == null) {
            throw new ApiRuntimeException(DeviceCode.IOT_PROPERTY_NOT_FOUND);
        }
        return getValue(identify, property.getData(), valueString);
    }

    public static Object getValue(String identify, DataType dataType, String valueString) {
        if (dataType == null || valueString == null) {
            return null;
        }

        if (dataType.getType().equals(ParamDataType.INT.value)) {
            MetaRule metaRule = (MetaRule) dataType.getRules();
            int value = Integer.valueOf(valueString);
            if (metaRule != null && ((StringUtils.isNotBlank(metaRule.getMax()) && value > Integer
                    .valueOf(metaRule.getMax()))
                    || StringUtils.isNotBlank(metaRule.getMin()) && value < Integer.valueOf(metaRule.getMin()))) {
                throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
            }
            return value;
        }
        // double
        else if (dataType.getType().equals(ParamDataType.DOUBLE.value)) {
            MetaRule metaRule = (MetaRule) dataType.getRules();
            double value = Double.valueOf(valueString);
            if (metaRule != null && ((StringUtils.isNotBlank(metaRule.getMax()) && value > Double
                    .valueOf(metaRule.getMax()))
                    || StringUtils.isNotBlank(metaRule.getMin()) && value < Double.valueOf(metaRule.getMin()))) {
                throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
            }
            return value;
        }

        // float
        else if (dataType.getType().equals(ParamDataType.FLOAT.value)) {
            MetaRule metaRule = (MetaRule) dataType.getRules();
            float value = Float.valueOf(valueString);
            // TODO 支持步长校验
            if (metaRule != null && ((StringUtils.isNotBlank(metaRule.getMax()) && value > Float
                    .valueOf(metaRule.getMax()))
                    || StringUtils.isNotBlank(metaRule.getMin()) && value < Float.valueOf(metaRule.getMin()))) {
                throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
            }
            return value;
        }

        // time
        else if (dataType.getType().equals(ParamDataType.TIME.value)) {
            if (Pattern.matches("(b[0-9]{10})", valueString)) {
                return valueString;
            }
            throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
        }

        // text
        else if (dataType.getType().equals(ParamDataType.TEXT.value)) {
            MetaRule metaRule = (MetaRule) dataType.getRules();
            if (metaRule != null && (StringUtils.isNotBlank(metaRule.getLength()) && valueString.length() > Integer
                    .valueOf(metaRule.getLength()))) {
                throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
            }
            return valueString;
        }

        // boolean
        else if (dataType.getType().equals(ParamDataType.BOOL.value)) {
            return valueString.equals("0") || valueString.equals("1") ? valueString : null;
        }

        // array
        else if (dataType.getType().equals(ParamDataType.ARRAY.value)) {
            ArrayRule metaRule = (ArrayRule) dataType.getRules();

            Object[] value = null;

            if (metaRule == null) {
                value = GsonUtils.fromJson(valueString, String[].class);
            } else if (metaRule.item.type.equals(ParamDataType.INT.value)) {
                value = GsonUtils.fromJson(valueString, Integer[].class);
            } else if (metaRule.item.type.equals(ParamDataType.DOUBLE.value)) {
                value = GsonUtils.fromJson(valueString, Double[].class);
            } else if (metaRule.item.type.equals(ParamDataType.FLOAT.value)) {
                value = GsonUtils.fromJson(valueString, Float[].class);
            } else if (metaRule.item.type.equals(ParamDataType.TEXT.value)) {
                value = GsonUtils.fromJson(valueString, String[].class);
            } else if (metaRule.item.type.equals(ParamDataType.BOOL.value)) {
                value = GsonUtils.fromJson(valueString, Boolean[].class);
            } else if (metaRule.item.type.equals(ParamDataType.TIME.value)) {
                value = GsonUtils.fromJson(valueString, String[].class);
            } else {
                throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
            }
            if (value == null || value.length < 1 || (metaRule != null && (value.length > Integer
                    .valueOf(metaRule.size)))) {
                throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
            }
            return value;
        }

        // enum
        else if (dataType.getType().equals(ParamDataType.ENUM.value)) {
            EnumRule metaRule = (EnumRule) dataType.getRules();
            if (metaRule.containsKey(valueString)) {
                return valueString;
            } else {
                throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
            }
        }

        // object
        else if (dataType.getType().equals(ParamDataType.OBJECT.value)) {
            JsonElement element = GsonUtils.fromJson(valueString, JsonElement.class);
            if (element.isJsonNull()) {
                throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
            } else {
                return valueString;
            }
        }

        // error type
        else {
            throw new DataErrorException(String.format(" Value of arg '%s' is wrong ", identify));
        }
    }

    public String getServiceAction(String serviceId) {
        Service service;
        if (TextUtils.isEmpty(serviceId)) {
            return null;
        }
        if (this.services == null) {
            return null;
        }
        if (this.services.isEmpty()) {
            return null;
        }
        Iterator<Service> iterator = this.services.iterator();
        do {
            if (!iterator.hasNext()) {
                return null;
            }
        } while (!serviceId.equalsIgnoreCase((service = iterator.next()).getId()));
        return service.getAction();
    }

    public String getEventAction(String eventId) {
        Event event;
        if (TextUtils.isEmpty(eventId)) {
            return null;
        }
        if (this.events == null) {
            return null;
        }
        if (this.events.isEmpty()) {
            return null;
        }
        Iterator<Event> iterator = this.events.iterator();
        do {
            if (!iterator.hasNext()) {
                return null;
            }
        } while (!eventId.equalsIgnoreCase((event = iterator.next()).getId()));
        return event.getAction();
    }

    public Event getEvent(String eventId) {
        Event event;
        if (TextUtils.isEmpty(eventId)) {
            return null;
        }
        if (this.events == null) {
            return null;
        }
        if (this.events.isEmpty()) {
            return null;
        }
        Iterator<Event> iterator = this.events.iterator();
        do {
            if (!iterator.hasNext()) {
                return null;
            }
        } while (!eventId.equalsIgnoreCase((event = iterator.next()).getId()));
        return event;
    }

    public Service getService(String serviceId) {

        Service service;

        if (TextUtils.isEmpty(serviceId)) {
            return null;
        }
        if (this.services == null) {
            return null;
        }
        if (this.services.isEmpty()) {
            return null;
        }
        Iterator<Service> iterator = this.services.iterator();
        do {
            if (!iterator.hasNext()) {
                return null;
            }
        } while (!serviceId.equalsIgnoreCase((service = iterator.next()).getId()));
        return service;
    }

    public Property getProp(String propId) {
        Property property;
        if (TextUtils.isEmpty(propId)) {
            return null;
        }
        if (this.properties == null) {
            return null;
        }
        if (this.properties.isEmpty()) {
            return null;
        }
        Iterator<Property> iterator = this.properties.iterator();
        do {
            if (!iterator.hasNext()) {
                return null;
            }
        } while (!propId.equalsIgnoreCase((property = iterator.next()).getId()));
        return property;
    }

    public boolean hasProp(String propId) {
        Property property;
        if (TextUtils.isEmpty(propId)) {
            return false;
        }
        if (this.properties == null) {
            return false;
        }
        if (this.properties.isEmpty()) {
            return false;
        }
        Iterator<Property> iterator = this.properties.iterator();
        do {
            if (!iterator.hasNext()) {
                return false;
            }
        } while (!propId.equalsIgnoreCase((property = iterator.next()).getId()));
        return true;
    }
}

