/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.solr.client.solrj.request;

import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.List;

import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.V2Response;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.util.NamedList;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestV2Request extends SolrCloudTestCase {
  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());


  @Before
  public void setupCluster() throws Exception {
    configureCluster(4)
        .addConfig("config", getFile("solrj/solr/collection1/conf").toPath())
        .configure();
  }
  
  @After
  public void afterTest() throws Exception {
    shutdownCluster();
  }

  public void assertSuccess(SolrClient client, V2Request request) throws IOException, SolrServerException {
    NamedList<Object> res = client.request(request);
    assertTrue("The request failed", res.get("responseHeader").toString().contains("status=0"));
  }

  @Test
  public void testIsCollectionRequest() {
    assertFalse(new V2Request.Builder("/collections").build().isPerCollectionRequest());
    assertFalse(new V2Request.Builder("/collections/a/shards").build().isPerCollectionRequest());
    assertFalse(new V2Request.Builder("/collections/a/shards/").build().isPerCollectionRequest());
    assertTrue(new V2Request.Builder("/collections/a/update").build().isPerCollectionRequest());
    assertEquals("a", new V2Request.Builder("/collections/a/update").build().getCollection());
    assertTrue(new V2Request.Builder("/c/a/update").build().isPerCollectionRequest());
    assertTrue(new V2Request.Builder("/c/a/schema").build().isPerCollectionRequest());
    assertFalse(new V2Request.Builder("/c/a").build().isPerCollectionRequest());
  }

  @Test
// 12-Jun-2018   @BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028")
  public void testHttpSolrClient() throws Exception {
    HttpSolrClient solrClient = new HttpSolrClient.Builder(
        cluster.getJettySolrRunner(0).getBaseUrl().toString()).build();
    doTest(solrClient);
    solrClient.close();
  }

  @Test
  // 12-Jun-2018 @BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028")
  public void testCloudSolrClient() throws Exception {
    doTest(cluster.getSolrClient());
  }

  private void doTest(SolrClient client) throws IOException, SolrServerException {
    assertSuccess(client, new V2Request.Builder("/collections")
        .withMethod(SolrRequest.METHOD.POST)
        .withPayload("{" +
            "  'create' : {" +
            "    'name' : 'test'," +
            "    'numShards' : 2," +
            "    'replicationFactor' : 2," +
            "    'config' : 'config'" +
            "  }" +
            "}").build());
    assertSuccess(client, new V2Request.Builder("/c").build());
    assertSuccess(client, new V2Request.Builder("/c/_introspect").build());


    String requestHandlerName = "/x" + random().nextInt();
    assertSuccess(client, new V2Request.Builder("/c/test/config")
        .withMethod(SolrRequest.METHOD.POST)
        .withPayload("{'create-requesthandler' : { 'name' : '" + requestHandlerName + 
            "', 'class': 'org.apache.solr.handler.DumpRequestHandler' , 'startup' : 'lazy'}}")
        .build());

    assertSuccess(client, new V2Request.Builder("/c/test").withMethod(SolrRequest.METHOD.DELETE).build());
    NamedList<Object> res = client.request(new V2Request.Builder("/c").build());
    List collections = (List) res.get("collections");
    
    // TODO: this is not guaranteed now - beast test if you try to fix
    // assertFalse( collections.contains("test"));

  }

  public void testV2Forwarding() throws Exception {
    SolrClient client = cluster.getSolrClient();
    assertSuccess(client, new V2Request.Builder("/collections")
        .withMethod(SolrRequest.METHOD.POST)
        .withPayload("{" +
            "  'create' : {" +
            "    'name' : 'v2forward'," +
            "    'numShards' : 1," +
            "    'replicationFactor' : 1," +
            "    'config' : 'config'" +
            "  }" +
            "}").build());

    ClusterState cs = cluster.getSolrClient().getClusterStateProvider().getClusterState();
    System.out.println("livenodes: " + cs.getLiveNodes());

    String[] node = new String[1];
    cs.getCollection("v2forward").forEachReplica((s, replica) -> node[0] = replica.getNodeName());

    //find a node that does not have a replica for this collection
    final String[] testNode = new String[1];
    cs.getLiveNodes().forEach(s -> {
      if (!s.equals(node[0])) testNode[0] = s;
    });

    String testServer = cluster.getSolrClient().getZkStateReader().getBaseUrlForNodeName(testNode[0]);
     V2Request v2r = new V2Request.Builder("/c/v2forward/_introspect")
        .withMethod(SolrRequest.METHOD.GET).build();

    try(HttpSolrClient client1 = new HttpSolrClient.Builder()
        .withBaseSolrUrl(testServer)
        .build()) {
      V2Response rsp = v2r.process(client1);
      assertEquals("0",rsp._getStr("responseHeader/status", null));
    }
  }

}
