#[Copyright 2025 ITwrx.
This file is part of Simple Site Manager.
Simple Site Manager is released under the GNU Affero General Public License 3.0.
See COPYING or <https://www.gnu.org/licenses/> for details.]#

import guildenstern/[epolldispatcher, httpserver], sqliteral
import "templates/error404.nimf", "templates/error500.nimf", "templates/reminders.nimf", "templates/reminder_create.nimf", "templates/reminder_update.nimf", "templates/login.nimf"
import helpers/db, helpers/global, helpers/form, helpers/auth
import models/reminder
import post_handlers/reminder_post_handler, post_handlers/login_post_handler, post_handlers/send_reminders_post_handler

db1.openDatabase(APP_NAME & ".db", [RemindersSchema, UsersSchema, SessionsSchema]);
var allReminders{.threadvar.}: seq[Reminder]

#uncomment, add creds to dev/create_user and compile+run once to add new admin user.
#import dev/create_user
#createNewUser()

proc handleGet() =
  {.gcsafe.}:
    try:      
      let uri = getUri()
      #overwrite cookie in browser when reply is performed, so form won't keep showing old input to this visitor if they don't POST again and also refresh for some reason.
      var cookieHeader: string
      if APP_MODE == "dev":
        cookieHeader = "Set-Cookie: form_result=" & "" & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;"
      else:
        cookieHeader = "Set-Cookie: form_result=" & "" & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;"
      if uri == "/login":          
        reply(loginTemplate(setVisitorCsrfToken(), getCookieFormResult()), [cookieHeader])
      if isAuthdAdmin():
        allReminders = getAllReminders()
        for reminder in allReminders:  
          if "/reminder/" & $reminder.id & "/update" == uri:
            reply(reminderUpdateTemplate(reminder.id, getUserPageCsrfToken(), getFormResult()), [cookieHeader])
        case uri:
          of "/":
            reply(remindersTemplate(allReminders, getUserPageCsrfToken(), getFormResult()), [cookieHeader])
          of "/create-reminder":
            reply(reminderCreateTemplate(getUserPageCsrfToken(), getFormResult()), [cookieHeader])
          of "/500":
            reply(error500Template(getUserPageCsrfToken(), getFormResult()), [cookieHeader])
          else:
            reply(error404Template(getUserPageCsrfToken()), [cookieHeader])  
      else:
        reply(Http302, [location("/login"), cookieHeader])
    except Exception as e:
      echo e.msg

proc handlePost() =
  {.gcsafe.}:
    try:
      let uri = getUri()
      if uri == "/send-reminders":
        sendRemindersPostHandler()
      let fr = getFormResult()
      #let csrfTokenInput = formInput("csrf_token")
      if uri == "/login":
        if isValidVisitorCsrfToken(formInput("csrf_token")):
          loginPostHandler()
        else:
          discard assignGeneralErrorFR("CSRF Token Validation Failure. Please try again (or report successive failures).")
          setFR()
          reply(Http302, [location("/login")])
      else:
        if isAuthdAdminPost():
          if isValidUserCsrfToken(formInput("csrf_token")):
            case uri
              of "/reminder/create":
                reminderCreatePostHandler()
              of "/reminder/update":
                reminderUpdatePostHandler()
              of "/reminder/delete":
                reminderDeletePostHandler()
              else:
                reply(error404Template(getUserPageCsrfToken()), ["Content-Type: text/html"])
          else:
            discard assignGeneralErrorFR("CSRF Token Validation Failure. Please try again (or report successive failures).")
            setFR()
            reply(Http302, [locationBack()])
        else:
          reply(Http302, [location("/login")])      
      
    except Exception as e:
      echo e.msg
  
let getserver = newHttpServer(handleGet, headerfields = ["cookie", "cookie"])
let postserver = newHttpServer(handlePost, loglevel = INFO, headerfields = ["origin", "cookie", "referer"])
if not epolldispatcher.start(getserver, 8096): quit()
if not epolldispatcher.start(postserver, 8097, threadpoolsize = 20): quit()
joinThreads(getserver.thread, postserver.thread)
