package com.tibbo.aggregate.common.expression.function;

import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import com.tibbo.aggregate.common.data.TimeZones;
import com.tibbo.aggregate.common.expression.Evaluator;
import com.tibbo.aggregate.common.expression.function.date.DateAddFunction;
import com.tibbo.aggregate.common.expression.function.date.DateCreateFunction;
import com.tibbo.aggregate.common.expression.function.date.DateDiffFunction;
import com.tibbo.aggregate.common.expression.function.date.DateFieldFunction;
import com.tibbo.aggregate.common.expression.function.date.FormatDateFunction;
import com.tibbo.aggregate.common.expression.function.date.PrintPeriodFunction;
import com.tibbo.aggregate.common.expression.function.date.TimeFunction;
import com.tibbo.aggregate.common.tests.CommonsFixture;
import com.tibbo.aggregate.common.tests.CommonsTestCase;
import com.tibbo.aggregate.common.util.TimeHelper;

public class TestCalendarFunctions extends CommonsTestCase
{
  private static final int year = 2014;
  private static final int month = Calendar.OCTOBER;
  private static final int day = 18;
  private static final int hour = 14;
  private static final int minutes = 55;
  private static final int seconds = 0;
  private static final String TS = "Asia/Dubai";
  private static final TimeZone TIME_ZONE = TimeZone.getTimeZone(TS);
  private static final GregorianCalendar GC = new GregorianCalendar(TIME_ZONE);
  static
  {
    GC.set(year, month, day, hour, minutes, seconds);
  }
  
  private Evaluator ev;
  
  public void setUp() throws Exception
  {
    super.setUp();
    ev = CommonsFixture.createTestEvaluator();
  }
  
  public void testDateCreateFunction() throws Exception
  {
    Object res = new DateCreateFunction().execute(ev, null, year, month, day, hour, minutes, seconds, TS);
    Date dres = (Date) res;
    
    GregorianCalendar calendar = new GregorianCalendar(TIME_ZONE);
    calendar.setTime(dres);
    assertEquals(hour, calendar.get(Calendar.HOUR_OF_DAY));
  }
  
  public void testDataCreateFunctionWithLongParameter() throws Exception
  {
    Long millis = 1L;
    Object res = new DateCreateFunction().execute(ev, null, year, month, day, hour, minutes, seconds, millis);
    ZonedDateTime zonedDateTime = ((Date) res).toInstant().atZone(ZoneId.of("UTC"));
    assertEquals(14, zonedDateTime.getHour());
  }
  
  public void testDateAddFunction() throws Exception
  {
    Object res = new DateAddFunction().execute(ev, null, GC.getTime(), 2, TimeHelper.NAME_HOUR, TS);
    Date dres = (Date) res;
    
    GregorianCalendar calendar = new GregorianCalendar(TIME_ZONE);
    calendar.setTime(dres);
    assertEquals(hour + 2, calendar.get(Calendar.HOUR_OF_DAY));
  }
  
  public void testDateFunction() throws Exception
  {
    Object y = new DateFieldFunction("year", ChronoField.YEAR, "").execute(ev, null, GC.getTime(), TS);
    Object h = new DateFieldFunction("hourOfDay", ChronoField.HOUR_OF_DAY, "").execute(ev, null, GC.getTime(), TS);
    
    assertEquals(year, y);
    assertEquals(hour, h);
  }
  
  public void testDateDiffFunction() throws Exception
  {
    long firstDate = System.currentTimeMillis();
    long secondDate = firstDate + TimeHelper.DAY_IN_MS;
    long result = TimeHelper.DAY_IN_MS;
    
    long diff = (long) new DateDiffFunction().execute(null, null, firstDate, secondDate, TimeHelper.MILLISECOND);
    
    assertEquals(result, diff);
  }
  
  public void testFormatDateFunction() throws Exception
  {
    long date = System.currentTimeMillis();
    String simpleDateFormatPattern = "yyyy.MM.dd HH:mm:ss";
    String timeZone = TimeZones.DEFAULT_TIME_ZONE_ID;
    
    SimpleDateFormat sdf = new SimpleDateFormat(simpleDateFormatPattern, Locale.ENGLISH);
    sdf.setTimeZone(TimeZone.getTimeZone(timeZone));
    String expected = sdf.format(new Date());
    
    String result = (String) new FormatDateFunction().execute(null, null, date, simpleDateFormatPattern, timeZone);
    
    assertEquals(expected, result);
  }
  
  public void testFormatDateFunctionWithEmptyParams() throws Exception
  {
    String result = (String) new FormatDateFunction().execute(null, null, 0, "", "");
    
    assertEquals("", result);
  }
  
  public void testTimeFunction() throws Exception
  {
    Date date = new Date();
    long expected = date.getTime();
    
    long result = (long) new TimeFunction().execute(null, null, date);
    
    assertEquals(expected, result);
  }
  
  public void testPrintPeriodFunction() throws Exception
  {
    long period = 1000;
    String expected = "1 Seconds";
    String result = (String) new PrintPeriodFunction().execute(null, null, period);
    
    assertEquals(expected, result);
  }
  
  public void testPrintPeriodFunctionWithTimeUnits() throws Exception
  {
    long period = 1000;
    String expected = "1 Seconds";
    String result = (String) new PrintPeriodFunction().execute(null, null, period, "1", "4");
    
    assertEquals(expected, result);
  }
}
