package com.avaje.tests.query.orderby;

import java.util.List;
import java.util.Set;

import com.avaje.tests.model.basic.Customer;
import com.avaje.tests.model.basic.ResetBasicData;
import org.junit.Assert;
import org.junit.Test;

import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Query;
import com.avaje.tests.model.basic.MRole;
import com.avaje.tests.model.basic.MUser;
import com.avaje.tests.model.basic.MUserType;

import static org.assertj.core.api.Assertions.assertThat;


public class TestOrderByWithDistinct extends BaseTestCase {

  @Test
  public void testOrderByValidation() {

    ResetBasicData.reset();

    Query<Customer> query = Ebean.find(Customer.class)
        .where()
          .eq("junk","blah")
          .eq("name","jim")
        .orderBy("id desc,path.that.does.not.exist,contacts.group.name asc");

    Set<String> unknownProperties = query.validate();
    assertThat(unknownProperties).isNotEmpty();
    assertThat(unknownProperties).hasSize(2);
    assertThat(unknownProperties).contains("junk","path.that.does.not.exist");

  }

	@Test
	public void test() {
		/*
		 * Original conversation:
		 * https://groups.google.com/forum/?fromgroups=#!topic/ebean/uuvi1btdCDQ%5B1-25-false%5D
		 * 
		 * This test exposes what may be a general problem with columns required by the order by phrase being omitted from the select.
		 * I'm not sure this exposes all causes of the problem.
		 */
		
		MUserType ut = new MUserType("md");
		Ebean.save(ut);
		MUser user1 = new MUser("one");
		user1.setUserType(ut);
		Ebean.save(user1);
		MUser user2 = new MUser("two");
		user2.setUserType(ut);
		Ebean.save(user2);
		
		MRole roleA = new MRole("A");
		Ebean.save(roleA);
		MRole roleB = new MRole("B");
		Ebean.save(roleB);
		
		user1.addRole(roleA);
		Ebean.save(user1);
		user2.addRole(roleB);
		Ebean.save(user2);
		
		Query<MUser> query = Ebean.find(MUser.class)
		    .fetch("userType","name")
				.where()
				.eq("roles.roleName", "A")
				.orderBy("userType.name, userName");
		List<MUser> list = query.findList();
		
		// select distinct t0.userid c0, t0.user_name c1, t1.id c2, t1.name c3 
		// from muser t0 
		// left join muser_type t1 on t1.id = t0.user_type_id
		// join mrole_muser u1z_ on u1z_.muser_userid = t0.userid 
		// join mrole u1 on u1.roleid = u1z_.mrole_roleid 
		// where u1.role_name = ? 
		// order by t1.name, t0.user_name; --bind(A)
		
		Assert.assertEquals(1, list.size());
		Assert.assertEquals(user1, list.get(0));
    String generatedSql = query.getGeneratedSql();
    Assert.assertTrue(generatedSql.contains("select distinct t0.userid")); // using distinct
    Assert.assertTrue(generatedSql.contains("order by t1.name,")); // name in order by
    Assert.assertTrue(generatedSql.contains("t1.name"));// name in select
		
		
		
		// repeat with slight variation, not sure this really produces a different execution path
		// this problem also manifests when autofetch eliminates properties from the select that aren't used in the objects
		// still need them to be present for purpose of order by
		// so here I'm "simulating" a scenario where autofetch has dropped userType.name
		query = Ebean.find(MUser.class)
				.setAutoTune(false)
				.select("userName")
				.fetch("userType","name")
				.where()
				.eq("roles.roleName", "A")
				.orderBy("userType.name");
		list = query.findList();
				
		Assert.assertEquals(1, list.size());
		Assert.assertEquals(user1, list.get(0));
		
		// select distinct t0.userid c0, t0.user_name c1, t1.id c2, t1.name c3 
		// from muser t0 
		// left join muser_type t1 on t1.id = t0.user_type_id
		// join mrole_muser u1z_ on u1z_.muser_userid = t0.userid 
		// join mrole u1 on u1.roleid = u1z_.mrole_roleid  
		// where u1.role_name = ? 
		// order by t1.name; --bind(A)
		
		generatedSql = query.getGeneratedSql();
    Assert.assertTrue(generatedSql.contains("select distinct t0.userid")); // using distinct
    Assert.assertTrue(generatedSql.contains("order by t1.name")); // name in order by
    Assert.assertTrue(generatedSql.contains("t1.name"));// name in select
		
	}

}
