import std/[times, osproc, strutils], smtp
import ../models/reminder, ../models/user, datetime

proc setFutureSendDate(reminderId: int) =
  var reminder: Reminder
  reminder = getReminderById(reminderId)
  var newSendDate: DateTime
  case reminder.repeatFreq:
    of "day":
      newSendDate = now() + 1.days
      reminder.sendDate = $format(newSendDate, "yyyy-MM-dd")
      updateReminderSendDate(reminder)
    of "week":
      newSendDate = nextWeekday(reminder.weeklyOn)
      reminder.sendDate = $format(newSendDate, "yyyy-MM-dd")
      updateReminderSendDate(reminder)
    of "month":
      if reminder.monthlyOnDay > 0:
        #create DateTime with current month and year and reminder.monthlyOnDay
        newSendDate = dateTime(year(now()), month(now()), reminder.monthlyOnDay)
        #add 1 month only if monthlyOnDay hasn't occured in current month yet.
        if reminder.monthlyOnDay < monthDay(now()):
          newSendDate = newSendDate + 1.months
        reminder.sendDate = $format(newSendDate, "yyyy-MM-dd")
        updateReminderSendDate(reminder)
      else:
        #monthly on week number and weekday. e.g. "third thursday of every month".
        newSendDate = nextMonthlyOnWeekdayOfWeek($reminder.monthlyOnWeekday, $reminder.monthlyOnWeek)
        reminder.sendDate = $format(newSendDate, "yyyy-MM-dd")
        updateReminderSendDate(reminder)
    of "year":
      #yearly on month and day.
      #string zeros (db artifacts) have a length of 1...
      if reminder.yearlyOnMonth.len() > 1:
        newSendDate = nextYearlyDate(reminder.yearlyOnMonth, reminder.yearlyOnDay)
        reminder.sendDate = $format(newSendDate, "yyyy-MM-dd")
        updateReminderSendDate(reminder)
      #yearly on weekday of week of month. e.g. third thursday of november of each year.
      else:
        newSendDate = nextYearlyOnWeekdayOfWeekOfMonth($reminder.yearlyOnWeekday, $reminder.yearlyOnWeek, $reminder.yearlyOnMonth2)
        reminder.sendDate = $format(newSendDate, "yyyy-MM-dd")
        updateReminderSendDate(reminder)
    else:
      echo "Invalid value for reminder.repeatFreq in setFutureSendDate()"
  clearAllReminders()

proc sendEmail(reminderMsg: string) =
  let userEmailAddress = getEmailByUserId("1")
  let headers = @[("From", "mailer@itwrx.org")]
  let msg = createMessage("Reminder from Forget-Me-Not", reminderMsg, @[userEmailAddress], mCc = @[""], otherHeaders = headers)
  {.cast(raises: []).}:
    let smtpConn = newSmtp(debug=false)
    smtpConn.connect("email.itwrx.org", Port 587)
    smtpConn.startTls()
    smtpConn.auth("mailer@itwrx.org", ".AQ8u((xB(AgZh^a`jEJ~W~{0Eq?fd$")
    #loop through email messages and send to reuse connection?
    smtpConn.sendmail("mailer@itwrx.org", @[userEmailAddress], $msg)
    #manually closing not necessary?
    smtpConn.close()

proc sendXMPP(reminderMsg: string) =
  var output: string
  var status: int
  (output, status) = execCmdEx("xmppc -m message chat itwrx@sec-chat.itwrx.org \"" & reminderMsg & "\"")
  if status != 0:
    #log this later instead.
    echo output
    echo "error sending XMPP msg"

#send reminders that haven't been sent yet and set new sendDate (if repeating).
proc sendReminders*() =
  let nowDT = now()
  let reminders = getAllReminders()
  for reminder in reminders:
    let sendDateDTString = $reminder.sendDate & " " & $reminder.sendTimeHr & ":" & $reminder.sendTimeMin & ":" & $reminder.sendTimeAmPm
    #single digits for minutes, as db send_time_min is integer and won't use "00", which results in runtime parse error.
    let sendDateDT = parse(sendDateDTString, "yyyy-M-d h:m:tt")
    #if sendDate is not in the future, it hasn't been sent yet (we are changing sendDate to future date during each send) and needs to be sent.
    if sendDateDT <= nowDT:
      #send reminder notification
      case reminder.notifyVia:
        of "email":
          sendEmail(reminder.message)
        of "xmpp":
          sendXMPP(reminder.message)
        else:
          sendXMPP(reminder.message)
          sendEmail(reminder.message)
      if reminder.repeats == 1:
        setFutureSendDate(reminder.id)
      else:
        deleteReminder(reminder.id)
        clearAllReminders()
