package org.etsi.osl.cridge;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.RouteBuilder;
import org.etsi.osl.tmf.rcm634.model.LogicalResourceSpecification;
import org.etsi.osl.tmf.rcm634.model.ResourceSpecification;
import org.etsi.osl.tmf.rcm634.model.ResourceSpecificationCreate;
import org.etsi.osl.tmf.ri639.model.LogicalResource;
import org.etsi.osl.tmf.ri639.model.Resource;
import org.etsi.osl.tmf.ri639.model.ResourceCreate;
import org.etsi.osl.tmf.ri639.model.ResourceUpdate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * @author ctranoris
 */
@Service
public class CatalogClient  extends RouteBuilder{


	private static final Logger logger = LoggerFactory.getLogger( CatalogClient.class.getSimpleName());

    @Autowired
    private ProducerTemplate template;

	
	@Value("${CATALOG_GET_RESOURCESPEC_BY_ID}")
	private String CATALOG_GET_RESOURCESPEC_BY_ID = "";

	@Value("${CATALOG_GET_RESOURCESPEC_BY_NAME_CATEGORY}")
	private String CATALOG_GET_RESOURCESPEC_BY_NAME_CATEGORY = "";


	@Value("${CATALOG_UPDADD_RESOURCESPEC}")
	private String CATALOG_UPDADD_RESOURCESPEC = "";
	
	
	@Value("${CATALOG_UPDADD_RESOURCE}")
	private String CATALOG_UPDADD_RESOURCE = "";
	

    @Value("${CATALOG_UPD_RESOURCE}")
    private String CATALOG_UPD_RESOURCE = "";

	@Value("${CATALOG_GET_RESOURCE_BY_ID}")
	private String CATALOG_GET_RESOURCE_BY_ID = "";
	
	
    //private ConcurrentHashMap<String, ResourceUpdate> resourcesToBeUpdated = new ConcurrentHashMap<>();
	

	@Override
	public void configure() throws Exception {


	  
//	  from( "timer://processUpdateResources?period=5000" )
//      .log(LoggingLevel.INFO, log, " process processUpdateResources!")
//      .to("log:DEBUG?showBody=true&showHeaders=true")
//      .bean( "catalogClient", "processUpdateResources()");
		
	
	}
	
	
	/**
	 * get  service spec by id from model via bus
	 * @param id
	 * @return
	 * @throws IOException
	 */
	public ResourceSpecification retrieveResourceSpecByNameCategoryVersion(String aName, String aCategory, String aVersion) {
		logger.info("will retrieve Resource Specification aName=" + aName   );
		
		try {
			Map<String, Object> map = new HashMap<>();
			map.put( "aname", aName);
			map.put( "acategory", aCategory);
			map.put( "aversion", aVersion);
			Object response = 
					template.requestBodyAndHeaders( CATALOG_GET_RESOURCESPEC_BY_NAME_CATEGORY, null, map);

			if ( !(response instanceof String)) {
				logger.error("Resource Specification object is wrong.");
				return null;
			}
			LogicalResourceSpecification sor = toJsonObj( (String)response, LogicalResourceSpecification.class); 
			//logger.debug("retrieveSpec response is: " + response);
			return sor;
			
		}catch (Exception e) {
			logger.error("Cannot retrieve Resource Specification details from catalog. " + e.toString());
		}
		return null;
	}
	
	/**
	 * get  service spec by id from model via bus
	 * @param id
	 * @return
	 * @throws IOException
	 */
	public ResourceSpecification retrieveResourceSpec(String specid) {
		logger.info("will retrieve Resource Specification id=" + specid   );
		
		try {
			Object response = template.
					requestBody( CATALOG_GET_RESOURCESPEC_BY_ID, specid);

			if ( !(response instanceof String)) {
				logger.error("Resource Specification object is wrong.");
				return null;
			}
			LogicalResourceSpecification sor = toJsonObj( (String)response, LogicalResourceSpecification.class); 
			//logger.debug("retrieveSpec response is: " + response);
			return sor;
			
		}catch (Exception e) {
			logger.error("Cannot retrieve Resource Specification details from catalog. " + e.toString());
		}
		return null;
	}
	

	public LogicalResourceSpecification createOrUpdateResourceSpecByNameCategoryVersion( ResourceSpecificationCreate s) {
		logger.info("will createOrUpdateResourceSpecByNameCategoryVersion "  );
		try {
			Map<String, Object> map = new HashMap<>();
			map.put("aname", s.getName());
			map.put("aversion", s.getVersion());
			map.put("acategory", s.getCategory());
			
			Object response = template.requestBodyAndHeaders( CATALOG_UPDADD_RESOURCESPEC, toJsonString(s), map);

			if ( !(response instanceof String)) {
				logger.error("ResourceSpecification  object is wrong.");
			}

			LogicalResourceSpecification rs = toJsonObj( (String)response, LogicalResourceSpecification.class); 
			return rs;
			
			
		}catch (Exception e) {
			logger.error("Cannot create ResourceSpecification");
			e.printStackTrace();
		}
		return null;
		
	}
	
	public Resource createOrUpdateResourceByNameCategoryVersion( ResourceCreate s) {
		logger.info("will createOrUpdateResourceByNameVersion a Resource "  );
		try {
			Map<String, Object> map = new HashMap<>();
			map.put("aname", s.getName());
			map.put("aversion", s.getResourceVersion());
			map.put("acategory", s.getCategory());
			
			Object response = template.requestBodyAndHeaders( CATALOG_UPDADD_RESOURCE, toJsonString(s), map);

			if ( !(response instanceof String)) {
				logger.error("Resource  object is wrong.");
			}

			logger.debug( response.toString() );
			try {
				LogicalResource rs = toJsonObj( (String)response, LogicalResource.class); 
				return rs;				
			}catch (Exception e) {
				logger.error("Cannot create LogicalResource");
				e.printStackTrace();
			}
			
			try {
				Resource rs = toJsonObj( (String)response, Resource.class); 
				return rs;				
			}catch (Exception e) {
				logger.error("Cannot create as Resource");
				e.printStackTrace();
			}
			
			
		}catch (Exception e) {
			logger.error("Cannot create Resource");
			e.printStackTrace();
		}
		return null;
		
	}
	

	
	private <T> T toJsonObj(String content, Class<T> valueType)  throws IOException {
	  ObjectMapper mapper = new ObjectMapper();
	  mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
	  return mapper.readValue( content, valueType);
	}

	private   String toJsonString(Object object) throws IOException {
	  ObjectMapper mapper = new ObjectMapper();
	  mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
	  return mapper.writeValueAsString(object);
	}

	

	public Resource updateResourceById(String oslResourceId, ResourceUpdate rs) {


	  logger.info("will update Resource : " + oslResourceId );
	  try {
	    Map<String, Object> map = new HashMap<>();
	    map.put("resourceId", oslResourceId );
	    map.put("triggerServiceActionQueue", false );

	    Object response = template.requestBodyAndHeaders( CATALOG_UPD_RESOURCE, toJsonString(rs), map);

	    if ( !(response instanceof String)) {
	      logger.error("Service Instance object is wrong.");
	    }

	    LogicalResource resourceInstance = toJsonObj( (String)response, LogicalResource.class); 
	    //logger.debug("createService response is: " + response);
	    return resourceInstance;


	  }catch (Exception e) {
        e.printStackTrace();
	    logger.error("Cannot update Service: " + oslResourceId + ": " + e.toString());
	  }
	  return null;
	}

//  public void updateResourceById(String oslResourceId, ResourceUpdate rs) {
//
//    resourcesToBeUpdated.put(oslResourceId, rs);
//   
//    
//  }
    
//  public void processUpdateResources() {
//    
//    resourcesToBeUpdated.forEach( (oslResourceId, rs) -> {
//      
//      logger.info("will update Resource : " + oslResourceId );
//      try {
//          Map<String, Object> map = new HashMap<>();
//          map.put("resourceId", oslResourceId );
//          map.put("triggerServiceActionQueue", false );
//          String json = toJsonString(rs);
//          Object response = template.requestBodyAndHeaders( CATALOG_UPD_RESOURCE, json, map);
//
//          if ( !(response instanceof String)) {
//              logger.error("Service Instance object is wrong.");
//          }
//
//          //LogicalResource resourceInstance = toJsonObj( (String)response, LogicalResource.class); 
//          //logger.debug("createService response is: " + response);
//          //return resourceInstance;
//          
//          resourcesToBeUpdated.remove(oslResourceId);
//          
//
//          logger.info("Updated successfully Resource : " + oslResourceId );
//      }catch (Exception e) {
//        e.printStackTrace();
//          logger.error("Cannot update Resource: " + oslResourceId + ": " + e.toString());
//      }
//      
//      
//      
//    });
//  }

}
