import LeanIO
open Std Async
open Std Http Server
open LeanIO
open LeanIO.Router
open LeanIO.Middlewares
open Lean

set_option linter.unusedVariables false

def uploadsDir : System.FilePath := "uploads"

structure LoginForm where
  username : String
  password : String
  role     : String := "user"
deriving FromForm

structure UploadResult where
  filename : String
  size     : Nat
  path     : String
  deriving ToJson

structure UploadResponse where
  fields : List (String × String)
  files  : List UploadResult
  deriving ToJson

def upload := POST "/upload" (mp : MultiPartForm) => do
  let mut fields : List (String × String) := []
  let mut files : List UploadResult := []
  IO.FS.createDirAll uploadsDir
  while let some entry := ← mp.nextEntry do
    match entry with
    | .field name value =>
      fields := (name, value) :: fields
    | .file file =>
      let savePath := uploadsDir / file.filename
      file.save savePath
      let mdata ← System.FilePath.metadata savePath
      files := { filename := file.filename, size := mdata.byteSize.toNat, path := toString savePath } :: files
  return { fields := fields.reverse, files := files.reverse : UploadResponse }

def login := POST "/login" (⟨form⟩ : Form LoginForm) => do
  return s!"logged in as {form.username} ({form.role})"

def main : IO Unit := Async.block do
  let addr : Net.SocketAddress := .v4 ⟨.ofParts 127 0 0 1, 8081⟩
  let router := Router.empty
    |>.addRoute upload
    |>.addRoute login
    |>.addMiddleware catchErrors
    |>.addMiddleware requestLogger
  let server ← router.serve addr { maxBodySize := 512 * 1024 * 1024 : Config }
  IO.println "Upload server on http://127.0.0.1:8081"
  server.waitShutdown
