package io.netfoundry.reporting.controller;

import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import io.netfoundry.auth.clientv2.AuthorizationContext;
import io.netfoundry.auth.clientv2.ResourceResolver;
import io.netfoundry.auth.domainv2.ancestry.ResourceIdPath;
import io.netfoundry.auth.domainv2.resourcetype.ResourceType;
import io.netfoundry.reporting.domain.Network;
import io.netfoundry.reporting.domain.NetworkUtilizationRequest;
import io.netfoundry.reporting.domain.Organization;
import io.netfoundry.reporting.exception.PermissionDeniedAdvice;
import io.netfoundry.reporting.service.ReportingElasticSearchService;
import io.netfoundry.reporting.util.ReportingTemplateEnum;
import io.netfoundry.reporting.util.ReportingUtility;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
public class NetworkUtiliztionController {
  private final ResourceResolver resourceResolver;
  private final ReportingElasticSearchService elasticSearchService;
  private final RestClient elasticRestClient;


  @Autowired
  public NetworkUtiliztionController(RestClient elasticClient, ResourceResolver resourceResolver,
      ReportingElasticSearchService elasticSearchService) {
    this.resourceResolver = resourceResolver;
    this.elasticSearchService = elasticSearchService;
    this.elasticRestClient = elasticClient;
  }


  @PostMapping(path = "/ncutilization", produces = {MediaType.APPLICATION_JSON_VALUE, "application/json"})
  public Object search(@RequestParam UUID networkGroupId,
      @RequestBody NetworkUtilizationRequest request) throws ElasticsearchException, IOException {
    AuthorizationContext authContext = AuthorizationContext.getContext();
    UUID networkId = request.getNetworkId();
    if (authContext == null) {
      throw new PermissionDeniedAdvice.PermissionDeniedException();
    }
    ResourceIdPath.Builder pathBuilder = null;
    ResourceType networkGroupResourceType = resourceResolver.getResourceType(Organization.class);
    if (networkId != null) {
      ResourceType networkResourceType = resourceResolver.getResourceType(Network.class);
      pathBuilder = ResourceIdPath
          .to(networkResourceType, networkId)
          .withParent(networkGroupResourceType, networkGroupId);
    } else {
      pathBuilder = ResourceIdPath.to(networkGroupResourceType, networkGroupId);
    }
    boolean authorized = authContext.isAuthorized(
        "io.netfoundry.network", "network", "read-elastic-search", pathBuilder.build());
    if (!authorized) {
      throw new PermissionDeniedAdvice.PermissionDeniedException();
    }
    Map<String, Object> params = elasticSearchService.getNetworkUtilizationTemplateParamMap(networkGroupId, request);
    if (params == null) throw new IllegalArgumentException();
    Request requestTemplate = new Request("POST", "/ncutilization-*/_search/template");
    String scriptId = ReportingTemplateEnum.nw_utilization_by_rx_and_tx_tmpl.name();
    String jsonPayload = ReportingUtility.toJson(params, scriptId);
    requestTemplate.setJsonEntity(jsonPayload);
    requestTemplate.setOptions(RequestOptions.DEFAULT.toBuilder().addHeader("Content-Type", "application/json").build());
    // Perform the search
    String response = EntityUtils.toString(elasticRestClient.performRequest(requestTemplate).getEntity());
    log.info("Template search request payload {}", jsonPayload);
    log.info("Template Search response {}", response);
    return response;
  }


}
