#[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/httpserver 
import nimword, jsony 
import std/[base64, sysrand]
import "../helpers/form", "../helpers/validation", "../helpers/auth", "../helpers/global", "../models/user", "../models/session"

proc loginPostHandler*() =  
  try: 
    var cookieHeader1, cookieHeader2: string
    let email = formInput("email")
    let password = formInput("password")   
    #validate form inputs
    vInput("email", @["required", "string", "email", "max:75"])
    vInput("password", @["required", "string", "min_complexity", "max:100"])
    var csrfTokenInput = formInput("csrf_token")
    #create formResult and redirect on validation errors.
    if formErrors.len > 0:
      addFormOldInput("email", formInput("email"))      
      #discard assignErrorFR(formErrors, formOldInputs, csrfTokenInput)
      discard assignErrorFR(formErrors, formOldInputs)
      let frJson = formResult.toJson()
      #let cookieHeader = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;"
      if APP_MODE == "dev":
        cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;"
      else:
        cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;"
      reply(Http303, [locationBack(), cookieHeader1])
    else:
      #inputs pass validation rules. let's see if the creds supplied are valid.
      let registeredUser = getUserByEmail(email)
      if registeredUser.email.len > 0:
        if password.isValidPassword(registeredUser.password):
          #create sessionId
          var sessionId = $urandom(32)
          sessionId = base64.encode(sessionId)
          #create session
          var userSession: Session
          userSession.sessionId = sessionId
          userSession.userId = registeredUser.id
          userSession.csrfToken = newCsrfToken()
          createUserSession(userSession)
          discard assignLoginSuccessFR()
          let frJson = formResult.toJson()
          #redirect, and set session cookie.  
          #will probably need to detect requested url for redirect (with static fallback) instead of just static location.
          #Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly
          #dev
          #let cookieHeader1 = "Set-Cookie: " & APP_NAME & "_session=" & sessionId & ";" & "HttpOnly;" & "SameSite=Lax;"
          #let cookieHeader2 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;"
          #prod
          #let cookieHeader1 = "Set-Cookie: " & APP_NAME & "_session=" & sessionId & ";" & "HttpOnly;" & "Secure=true;" & "SameSite=Lax;"
          #let cookieHeader2 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;" 
          if APP_MODE == "dev":
            cookieHeader1 = "Set-Cookie: " & APP_NAME & "_session=" & sessionId & ";" & "HttpOnly;" & "SameSite=Lax;"
            cookieHeader2 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;"
          else:
            cookieHeader1 = "Set-Cookie: " & APP_NAME & "_session=" & sessionId & ";" & "HttpOnly;" & "Secure=true;" & "SameSite=Lax;"
            cookieHeader2 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;"
          #headers are just an openarray of strings.
          reply(Http303, [location("/"), cookieHeader1, cookieHeader2])
        else:
          #password supplied did not match password in DB for supplied email address. redirect back to login with creds error.        
          #create a formError.
          formError.fieldName = "password"
          formError.fieldMessage = "Entered password is not valid."
          #add it to formErrors seq.
          formErrors.add(formError)        
          formResult.message = "Authentication error."
          formResult.messageClass = "text-red-500"
          formResult.errors = toJson(formErrors)
          formResult.oldInputs = getOldInputJson()
          let frJson = formResult.toJson()
          #let cookieHeader = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;"
          #let cookieHeader = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;"          
          if APP_MODE == "dev":            
            cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;"
          else:            
            cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;"
          reply(Http303, [locationBack(), cookieHeader1])
      else:
        formError.fieldName = "email"
        formError.fieldMessage = "No user found with supplied email address."
        #add it to formErrors seq.
        formErrors.add(formError)        
        formResult.message = "Authentication error."
        formResult.messageClass = "text-red-500"
        formResult.errors = toJson(formErrors)
        formResult.oldInputs = getOldInputJson()
        let frJson = formResult.toJson()
        #let cookieHeader = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;"
        if APP_MODE == "dev":            
          cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "path=/;" & "SameSite=Lax;"
        else:            
          cookieHeader1 = "Set-Cookie: form_result=" & frJson & ";" & "HttpOnly;" & "Secure=true;" & "path=/;" & "SameSite=Lax;"
        reply(Http303, [locationBack(), cookieHeader1])
          
  except Exception as e:
    echo e.msg
    #reply(Http500)
    discard assignGeneralErrorFR(e.msg)
    setFR()
    reply(Http303, [location("/500")])
