package cz.hsrs.db.util;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import cz.hsrs.core.WebServiceException;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import cz.hsrs.db.model.NoItemFoundException;
import cz.hsrs.db.model.Phenomenon;
import cz.hsrs.db.model.Sensor;
import cz.hsrs.db.model.insert.UnitInsert;
import cz.hsrs.db.pool.SQLExecutor;


/**
 * @author mkepka
 */
public class ManagementUtil extends DBUtil {

    public UnitInsert deleteSensor(JSONObject payload) throws NoItemFoundException, SQLException {
        if(payload.containsKey("unit")) {
            JSONObject unitJson = payload.getJSONObject("unit");
            if (!unitJson.containsKey("unit_id")) {
                throw new NoItemFoundException("Attribute 'unit_id' is required.");
            }
            long unitId = unitJson.getLong("unit_id");

            if (payload.containsKey("sensors")) {
                JSONArray sensorsJsonArray = payload.getJSONArray("sensors");
                long[] sensorIds = new long[sensorsJsonArray.size()];
                for (int i = 0; i < sensorsJsonArray.size(); i++) {
                    JSONObject sensorJson = sensorsJsonArray.getJSONObject(i);
                    if (!sensorJson.containsKey("sensor_id")) {
                        throw new NoItemFoundException("Attribute 'sensor_id' is required.");
                    }
                    sensorIds[i] = sensorJson.getLong("sensor_id");
                }

                List<Sensor> sensors = new ArrayList<>(sensorIds.length);
                for (long sensorId : sensorIds) {
                    String sql = String.format("DELETE FROM units_to_sensors WHERE sensor_id = %s AND unit_id = %s", sensorId, unitId);
                    int result = SQLExecutor.executeUpdate(sql);
                    //- delete sensor pokud je pouze u teto jednotky
                    //- delete pouze units_to_sensors pokud je u vice jednotek - typ senzoru - OK
                    if (result > 0) {
                        sensors.add(new Sensor(sensorId, null, null, null));
                    }
                }
                return new UnitInsert(unitId, null, sensors);
            } else {
                throw new NoItemFoundException("Attribute 'sensors' is required.");
            }
        } else {
            throw new NoItemFoundException("Attribute 'unit' is required.");
        }
    }

    public Long deleteUnit(JSONObject payload) throws NoItemFoundException, SQLException {
        if(payload.containsKey("unit")) {
            JSONObject unitJson = payload.getJSONObject("unit");
            if (!unitJson.containsKey("unit_id")) {
                throw new NoItemFoundException("Attribute 'unit_id' is required.");
            }
            long unitId = unitJson.getLong("unit_id");
            final UnitUtil unitUtil = new UnitUtil();
            int result = unitUtil.deleteUnit(unitId);
            return result > 0 ? unitId : null;
        } else {
            throw new NoItemFoundException("Attribute 'unit' is required.");
        }
    }

    public UnitInsert insertSensor(JSONObject payload, String username) throws NoItemFoundException, SQLException {
        if(payload.containsKey("unit")) {
            JSONObject unitJson = payload.getJSONObject("unit");
            if (!unitJson.containsKey("unit_id")) {
                throw new NoItemFoundException("Attribute 'unit_id' is required.");
            }
            long unitId = unitJson.getLong("unit_id");

            List<Sensor> sensors;
            if(payload.containsKey("sensors")){
                JSONArray sensorsJsonArray = payload.getJSONArray("sensors");
                sensors = processSensors(sensorsJsonArray);
            } else {
                throw new NoItemFoundException("Attribute 'sensors' is required.");
            }

            for (Sensor sensor : sensors) {
                sensor.insertToDb(unitId);
            }
            return new UnitInsert(unitId, null, sensors);
        } else {
            throw new NoItemFoundException("Attribute 'unit' is required.");
        }
    }

    public UnitInsert updateSensor(JSONObject payload) throws NoItemFoundException, SQLException {
        if (payload.containsKey("unit")) {
            JSONObject unitJson = payload.getJSONObject("unit");
            if (!unitJson.containsKey("unit_id")) {
                throw new NoItemFoundException("Attribute 'unit_id' is required.");
            }
            long unitId = unitJson.getLong("unit_id");

            List<Sensor> sensors;
            if(payload.containsKey("sensors")){
                JSONArray sensorsJsonArray = payload.getJSONArray("sensors");
                if (sensorsJsonArray.isEmpty()) {
                    throw new NoItemFoundException("Attribute 'sensors' is empty.");
                }
                sensors = processSensors(sensorsJsonArray);
            } else {
                throw new NoItemFoundException("Attribute 'sensors' is required.");
            }

            throw new WebServiceException(425, "Update of the sensor is not supported yet.");
            /*
            for (Sensor sensor : sensors) {
                long sensorId = sensor.getSensorId();
                // 2. iterace
                // TODO UPDATE sensor attribute in the database

            }
            return new UnitInsert(unitId, null, sensors);

             */

        } else {
            throw new NoItemFoundException("Attribute 'unit' is required.");
        }
    }

    public UnitInsert updateUnit(JSONObject payload) throws NoItemFoundException, SQLException {
        if (payload.containsKey("unit")) {
            JSONObject unitJson = payload.getJSONObject("unit");
            if (!unitJson.containsKey("unit_id")) {
                throw new NoItemFoundException("Attribute 'unit_id' is required.");
            }
            long unitId = unitJson.getLong("unit_id");
            String unitDsc = unitJson.getString("description");
            String sql = String.format("UPDATE units SET description = '%s' WHERE unit_id = %s", unitDsc, unitId);
            int result = SQLExecutor.executeUpdate(sql);
            return result > 0 ? new UnitInsert(unitId, unitDsc, null) : null;
        } else {
            throw new NoItemFoundException("Attribute 'unit' is required.");
        }
    }
	
	public UnitInsert insertUnit(JSONObject payload, String username) throws NoItemFoundException, SQLException {
		if(payload.containsKey("unit")) {
			JSONObject unitO = payload.getJSONObject("unit");
			Long unitIdVal = unitO.containsKey("unit_id") ? unitO.getLong("unit_id") : null;
	        String descVal = unitO.containsKey("description") ? unitO.getString("description") : null;

	        List<Sensor> sensors = null;
	        if(payload.containsKey("sensors")){
	        	JSONArray sensorsArr = payload.getJSONArray("sensors");
	            sensors = processSensors(sensorsArr);
	        }

	        if(unitIdVal == null && descVal == null){
	        	throw new NoItemFoundException("Unit must be defined by ID or by description!");
	        } else{
	        	UnitInsert unit = new UnitInsert(unitIdVal, descVal, sensors);
	            Integer groupId = UserUtil.getUserGroupId(username);
                return unit.insertUnitToDB(groupId);
	        }
		} else {
			throw new NoItemFoundException("Payload doesn't contain unit part!");
		}
	}

    private List<Sensor> processSensors(JSONArray sensArr) throws NoItemFoundException{
        List<Sensor> sensorsList = new LinkedList<Sensor>();
        for(int i = 0;i < sensArr.size(); i++){
            JSONObject sensorObj = sensArr.getJSONObject(i);
            Long sensorId = sensorObj.containsKey("sensor_id") ? sensorObj.getLong("sensor_id") : null;
            String sensorName = sensorObj.containsKey("sensor_name") ? sensorObj.getString("sensor_name") : null;
            String sensorType = sensorObj.containsKey("sensor_type") ? sensorObj.getString("sensor_type") : null;

            Phenomenon phen = null;
            if(sensorObj.containsKey("phenomenon")){ 
                JSONObject phenO = sensorObj.getJSONObject("phenomenon");
                String phenId = phenO.containsKey("phenomenon_id") ? phenO.getString("phenomenon_id") : null;
                String phenName = phenO.containsKey("phenomenon_name") ? phenO.getString("phenomenon_name") : null;
                String uom = phenO.containsKey("uom") ? phenO.getString("uom") : null;

                if((phenName == null && uom != null) || (phenName != null && uom == null)){
                    throw new NoItemFoundException("Phenomenon must be defined by ID or by name and UoM!");
                } else{
                    phen = new Phenomenon(phenId, phenName, uom, null);
                }
            }
            if(sensorName != null && sensorType != null && phen != null){
                if(sensorId != null){
                    sensorsList.add(new Sensor(sensorId, sensorName, sensorType, phen));
                } else{
                    sensorsList.add(new Sensor(sensorName, sensorType, phen));
                }
            } else{
                if(sensorId != null){
                    sensorsList.add(new Sensor(sensorId, null, null, null));
                } else{
                    throw new NoItemFoundException("Sensor must be defined by ID or by sensor_name, sensor_type and phenomenon!");
                }
            }
        }
        return sensorsList;
    }
}