local util = {}
util.TimeFormat = {
  YMD_HMS = 1,
  YMD_HM = 2,
  YMD = 3,
  MD_HM = 4,
  MD = 5
}
util.DAY_WHOLE = 86400
util.DAY = 43200
util.HOUR = 3600
util.MINUTE = 60

function util.getSecondInfo(second)
  local day = math.floor(second / util.DAY_WHOLE)
  second = second % util.DAY_WHOLE
  local hour = math.floor(second / util.HOUR)
  second = second % util.HOUR
  local minute = math.floor(second / util.MINUTE)
  local second = second % util.MINUTE
  return {
    day = day,
    hour = hour,
    minute = minute,
    second = second
  }
end

function util.getDateInfo(time)
  return os.date("*t", time)
end

util.secondToStringShowType = {NORMAL = 1, TWO_UNIT = 2}

function util.secondToString(second, showType)
  showType = showType or util.secondToStringShowType.NORMAL
  local info = util.getSecondInfo(second)
  if showType == util.secondToStringShowType.NORMAL then
    if info.day > 0 then
      return string.format("%dd %02d:%02d:%02d", info.day, info.hour, info.minute, info.second)
    elseif 0 < info.hour then
      return string.format("%d:%02d:%02d", info.hour, info.minute, info.second)
    end
    return string.format("%02d:%02d", info.minute, info.second)
  elseif showType == util.secondToStringShowType.TWO_UNIT then
    if info.day > 0 then
      return L_WordsTpl:getValue("ui_common_time_01", {
        [0] = info.day,
        [1] = info.hour
      })
    elseif 0 < info.hour then
      return L_WordsTpl:getValue("ui_common_time_02", {
        [0] = info.hour,
        [1] = info.minute
      })
    elseif 0 < info.minute then
      return L_WordsTpl:getValue("ui_common_time_03", {
        [0] = info.minute,
        [1] = info.second
      })
    else
      return L_WordsTpl:getValue("ui_common_time_04", {
        [0] = info.second
      })
    end
  end
end

function util.getTimeLimit(second)
  local day = math.floor(second / 86400)
  return day
end

function util.getTimeLimitStr(second)
  local day = util.getTimeLimit(second)
  if day == 0 then
    return "<1"
  else
    return tostring(day)
  end
end

function util.getServerTime()
  return math.ceil(C_TimeUtility.NowServer)
end

function util.getServerTimeWithFloor()
  return math.floor(C_TimeUtility.NowServer)
end

function util.getServerTimeOfDate(timestamp)
  return math.ceil(C_TimeUtility.TimestampOfDate(timestamp))
end

function util.getServerTimeOfDateTime(timestamp)
  print("getServerTimeOfDateTime")
  print(timestamp)
  return C_TimeUtility.DateTimeOfDate(timestamp)
end

function util.getServerTimeOfToday()
  return math.ceil(C_TimeUtility.TimestampOfToday())
end

function util.parseConfigDatetime(cfgDt)
  return math.ceil(C_TimeUtility.TimeStringToTimestamp(cfgDt, "yyyyMMdd-HHmmss"))
end

function util.getDisplayTime(t, format)
  t = t or util.getServerTime()
  format = format or util.TimeFormat.YMD_HMS
  if format == util.TimeFormat.YMD_HMS then
    return os.date("%Y-%m-%d %H:%M:%S", math.ceil(t))
  elseif format == util.TimeFormat.YMD_HM then
    return os.date("%Y-%m-%d %H:%M", math.ceil(t))
  elseif format == util.TimeFormat.YMD then
    return os.date("%Y-%m-%d", math.ceil(t))
  elseif format == util.TimeFormat.MD_HM then
    return os.date("%m-%d %H:%M", math.ceil(t))
  elseif format == util.TimeFormat.MD then
    return os.date("%m-%d", math.ceil(t))
  end
end

function util.getWaterMaskTime()
  local t = util.getServerTime()
  return os.date("%Y-%m-%d %H:%M:%S", math.ceil(t))
end

function util.getLeftTimeDisplay(endTime)
  if endTime == nil or endTime == 0 then
    return
  end
  local now = util.getServerTime()
  local leftTime = endTime - now
  if 86400 <= leftTime then
    return L_WordsTpl:getValue("ui_timeUtil_03", {
      [0] = util.getDisplayTime(endTime, util.TimeFormat.YMD_HM)
    })
  elseif 3600 <= leftTime then
    local hrs = math.floor(leftTime / 3600)
    return nil, L_WordsTpl:getValue("ui_timeUtil_01", {
      [0] = hrs
    })
  elseif 60 <= leftTime then
    local mins = math.floor(leftTime / 60)
    return nil, L_WordsTpl:getValue("ui_timeUtil_02", {
      [0] = mins
    })
  else
    return nil, "\229\183\178\229\136\176\230\156\159"
  end
end

function util.getLeftTimeString(endTime, hideSecond)
  if endTime == nil then
    return
  end
  local now = util.getServerTime()
  local leftTime = endTime - now
  local info = util.getSecondInfo(leftTime)
  if 86400 <= leftTime then
    if hideSecond then
      return L_WordsTpl:getValue("ui_timeUtil_04", {
        [0] = info.day,
        [1] = info.hour,
        [2] = info.minute
      })
    end
    return L_WordsTpl:getValue("ui_timeUtil_05", {
      [0] = info.day,
      [1] = info.hour
    })
  elseif 3600 <= leftTime then
    return L_WordsTpl:getValue("ui_timeUtil_06", {
      [0] = info.hour,
      [1] = info.minute
    })
  else
    if hideSecond then
      if 60 <= leftTime then
        return L_WordsTpl:getValue("ui_timeUtil_10", {
          [0] = info.minute
        })
      end
      return L_WordsTpl:getValue("ui_timeUtil_12")
    end
    return L_WordsTpl:getValue("ui_timeUtil_07", {
      [0] = info.minute,
      [1] = info.second
    })
  end
end

function util.getLeftTimeString2(endTime)
  if endTime == nil then
    return
  end
  local now = util.getServerTime()
  local leftTime = endTime - now
  local info = util.getSecondInfo(leftTime)
  util.getLeftTimeString2StrList = util.getLeftTimeString2StrList or {
    [1] = "ui_timeUtil_08",
    [2] = "ui_timeUtil_09",
    [3] = "ui_timeUtil_10",
    [4] = "ui_timeUtil_11"
  }
  util.getLeftTimeString2TimeList = util.getLeftTimeString2TimeList or {}
  util.getLeftTimeString2StrIndexList = util.getLeftTimeString2StrIndexList or {}
  table.clear(util.getLeftTimeString2TimeList)
  table.clear(util.getLeftTimeString2StrIndexList)
  if info.day > 0 then
    table.insert(util.getLeftTimeString2TimeList, info.day)
    table.insert(util.getLeftTimeString2StrIndexList, 1)
  end
  if 0 < info.hour then
    table.insert(util.getLeftTimeString2TimeList, info.hour)
    table.insert(util.getLeftTimeString2StrIndexList, 2)
  end
  if 0 < info.minute then
    table.insert(util.getLeftTimeString2TimeList, info.minute)
    table.insert(util.getLeftTimeString2StrIndexList, 3)
  end
  if 0 < info.second then
    table.insert(util.getLeftTimeString2TimeList, info.second)
    table.insert(util.getLeftTimeString2StrIndexList, 4)
  end
  local paramsNum = #util.getLeftTimeString2TimeList
  if 2 <= paramsNum then
    return L_WordsTpl:getValue(util.getLeftTimeString2StrList[util.getLeftTimeString2StrIndexList[1]], {
      [0] = util.getLeftTimeString2TimeList[1]
    }) .. L_WordsTpl:getValue(util.getLeftTimeString2StrList[util.getLeftTimeString2StrIndexList[2]], {
      [0] = util.getLeftTimeString2TimeList[2]
    })
  elseif paramsNum == 1 then
    return L_WordsTpl:getValue(util.getLeftTimeString2StrList[util.getLeftTimeString2StrIndexList[1]], {
      [0] = util.getLeftTimeString2TimeList[1]
    })
  elseif paramsNum == 0 then
    return L_WordsTpl:getValue("ui_timeUtil_11", {
      [0] = "0"
    })
  end
end

function util.getLeftTimeStringShort(endTime)
  if endTime == nil then
    return
  end
  local now = util.getServerTime()
  local leftTime = endTime - now
  local info = util.getSecondInfo(leftTime)
  if 86400 <= leftTime then
    return L_WordsTpl:getValue("ui_timeUtil_08", {
      [0] = info.day
    })
  elseif 3600 <= leftTime then
    return L_WordsTpl:getValue("ui_timeUtil_09", {
      [0] = info.hour
    })
  else
    return L_WordsTpl:getValue("ui_timeUtil_10", {
      [0] = info.minute
    })
  end
end

function util.getLeftTime(endTime)
  if endTime == nil then
    return
  end
  local now = util.getServerTime()
  local leftTime = endTime - now
  local info = util.getSecondInfo(leftTime)
  return string.format("%.2d:%.2d:%.2d", info.hour, info.minute, info.second)
end

function util.secondToLangString(second)
  local info = util.getSecondInfo(second)
  if 86400 <= second then
    return L_WordsTpl:getValue("ui_timeUtil_05", {
      [0] = info.day,
      [1] = info.hour
    })
  elseif 3600 <= second then
    return L_WordsTpl:getValue("ui_timeUtil_06", {
      [0] = info.hour,
      [1] = info.minute
    })
  elseif second < 60 then
    return L_WordsTpl:getValue("ui_timeUtil_11", {
      [0] = info.second
    })
  else
    return L_WordsTpl:getValue("ui_timeUtil_07", {
      [0] = info.minute,
      [1] = info.second
    })
  end
end

function util.isSameDay(time1, time2)
  local time_clock = 0
  if L_Config:getConfig("game", "DAILY_REFRESH_TIME") then
    time_clock = tonumber(L_Config:getConfig("game", "DAILY_REFRESH_TIME"))
  end
  return C_TimeUtility.IsSameDay(time1 - time_clock * 3600, time2 - time_clock * 3600)
end

function util.isSameWeek(time1, time2)
  local time_clock = 0
  if L_Config:getConfig("game", "DAILY_REFRESH_TIME") then
    time_clock = tonumber(L_Config:getConfig("game", "DAILY_REFRESH_TIME"))
  end
  local dateA = os.date("*t", time1 - 86400 - time_clock * 3600)
  local dateB = os.date("*t", time2 - 86400 - time_clock * 3600)
  local diff = (time1 - time2) / 86400
  local wdayA = dateA.wday
  local wdayB = dateB.wday
  if diff < 0 and -7 < diff and wdayA <= wdayB or 0 <= diff and diff < 7 and wdayA >= wdayB then
    return true
  end
  return false
end

function util.isSameMonth(time1, time2)
  local time_clock = 0
  if L_Config:getConfig("game", "DAILY_REFRESH_TIME") then
    time_clock = tonumber(L_Config:getConfig("game", "DAILY_REFRESH_TIME"))
  end
  local dateA = os.date("*t", time1 - time_clock * 3600)
  local dateB = os.date("*t", time2 - time_clock * 3600)
  return dateA.month == dateB.month
end

function util.getLeftDayAndHour(endTime)
  local now = util.getServerTime()
  local leftTime = endTime - now
  if leftTime <= 0 then
    return nil, nil, leftTime
  end
  if 86400 <= leftTime then
    local day = math.floor(leftTime / 86400)
    return true, day, leftTime
  elseif 3600 <= leftTime then
    local hrs = math.floor(leftTime / 3600)
    return false, hrs, leftTime
  else
    return false, 1, leftTime
  end
end

function util.getOfflineTimeDisplay(onlineTime, offlineTime)
  if 0 <= onlineTime - offlineTime then
    return L_GameUtil.fillColor(L_WordsTpl:getValue("ui_timeMessage_02"), L_Const.colorHtml.green01)
  else
    local now = util.getServerTime()
    local offlineTimeDif = now - offlineTime
    local hour = math.floor(offlineTimeDif / util.HOUR)
    local minute = math.floor(offlineTimeDif / util.MINUTE)
    if hour < 1 then
      return L_GameUtil.fillColor(string.format(L_WordsTpl:getValue("ui_timeMessage_03"), minute), L_Const.colorHtml.grey01)
    elseif 1 <= hour and hour < 30 then
      return L_GameUtil.fillColor(string.format(L_WordsTpl:getValue("ui_timeMessage_04"), hour), L_Const.colorHtml.grey01)
    else
      return L_GameUtil.fillColor(L_WordsTpl:getValue("ui_timeMessage_05"), L_Const.colorHtml.grey01)
    end
  end
end

function util.getChatDisplayTime(t)
  local nowTime = util.getServerTime()
  if C_TimeUtility.IsSameDay(t, nowTime) then
    return os.date("%H:%M", math.ceil(t))
  else
    return os.date("%Y-%m-%d %H:%M", math.ceil(t))
  end
end

function util.getDaysToSecond(day)
  if day < 0 then
    return 0
  end
  return util.DAY * day
end

function util.getHourToSecond(hour)
  if hour < 0 then
    return 0
  end
  return util.HOUR * hour
end

function util.getMinuteSecond(minute)
  if minute < 0 then
    return 0
  end
  return util.MINUTE * minute
end

function util.getDateTimeInfor(param)
  local second = param % 100
  local minute = param / 100 % 100
  local hour = param / 10000
  return hour, minute, second
end

function util.getNextDayTime(hour, curTime)
  if curTime == nil then
    curTime = util.getServerTime()
  end
  local dateTime = util.getDateInfo(curTime)
  if hour <= dateTime.hour then
    dateTime.day = dateTime.day + 1
  end
  dateTime.hour = hour
  dateTime.min = 0
  dateTime.sec = 0
  return os.time(dateTime)
end

function util.getNextDayRefreshTime()
  local dateTime = util.getDateInfo(util.getServerTime())
  local refreshHour = L_Config:getConfig("game", "DAILY_REFRESH_TIME")
  if refreshHour <= dateTime.hour then
    dateTime.day = dateTime.day + 1
  end
  dateTime.hour = refreshHour
  dateTime.min = 0
  dateTime.sec = 0
  return os.time(dateTime)
end

function util.getNextDateTime(nextDayOfWeek, hour, minute, second)
  local timestamp = util.getServerTime()
  local currentDayOfWeek = tonumber(os.date("%w", timestamp))
  local daysUntilNextDayOfWeek = (nextDayOfWeek - currentDayOfWeek + 7) % 7
  local nextDateTimestamp = timestamp + 86400 * daysUntilNextDayOfWeek
  local nextDateTime = util.getDateInfo(nextDateTimestamp)
  nextDateTime.hour = hour or 0
  nextDateTime.min = minute or 0
  nextDateTime.sec = second or 0
  if timestamp > os.time(nextDateTime) then
    nextDateTime.day = nextDateTime.day + 7
  end
  return nextDateTime
end

function util.getLeftWeekRefreshTime(hideSecond)
  local refreshWeekday = 1
  if L_Config:getConfig("game", "WEEKLY_REFRESH_TIME") then
    refreshWeekday = tonumber(L_Config:getConfig("game", "WEEKLY_REFRESH_TIME"))
  end
  local refreshHour = L_Config:getConfig("game", "DAILY_REFRESH_TIME")
  local nextDate = util.getNextDateTime(refreshWeekday, refreshHour)
  return util.getLeftTimeString(os.time(nextDate), hideSecond)
end

function util.getLeftDayRefreshTime()
  local nextDate = 0
  local curTime = util.getServerTime()
  local refreshPoint = L_Config:getConfig("game", "DAILY_REFRESH_TIME")
  local timeOfDay = (curTime + 28800) % util.DAY_WHOLE
  local dayTime = curTime - timeOfDay
  local nextTimeStep = refreshPoint * 3600
  if timeOfDay < nextTimeStep then
    nextDate = dayTime + nextTimeStep
  else
    nextDate = dayTime + util.DAY_WHOLE + nextTimeStep
  end
  return util.getLeftTimeString(nextDate)
end

function util.getDateTimeStamp(timeDate)
  local date = string.split(timeDate, "-")
  local yearInfo = date[1]
  local dayInfo = date[2]
  local year = tostring(string.sub(yearInfo, 1, 4))
  local month = tostring(string.sub(yearInfo, 5, 6))
  local day = tostring(string.sub(yearInfo, 7, 8))
  local hour = tostring(string.sub(dayInfo, 1, 2))
  local min = tostring(string.sub(dayInfo, 3, 4))
  local sec = tostring(string.sub(dayInfo, 5, 6))
  local timeStamp = os.time({
    day = day,
    month = month,
    year = year,
    hour = hour,
    min = min,
    sec = sec
  })
  return timeStamp
end

function util.getCurWeekDay(timeStamp)
  timeStamp = timeStamp or util.getServerTime()
  local weekdayNumber = os.date("%w", math.ceil(timeStamp))
  return tonumber(weekdayNumber)
end

return util
