/// Views for request pages and components
module MyPrayerJournal.Views.Request

open Giraffe.ViewEngine
open Giraffe.ViewEngine.Htmx
open MyPrayerJournal
open NodaTime
open System

/// Create a request within the list
let reqListItem now req =
  let reqId      = RequestId.toString req.requestId
  let isAnswered = req.lastStatus = Answered
  let isSnoozed  = req.snoozedUntil > now
  let isPending  = (not isSnoozed) && req.showAfter > now
  let btnClass   = _class "btn btn-light mx-2"
  let restoreBtn (link : string) title =
    button [ btnClass; _hxPatch $"/request/{reqId}/{link}"; _title title ] [ icon "restore" ]
  div [ _class "list-group-item px-0 d-flex flex-row align-items-start"; _hxTarget "this"; _hxSwap HxSwap.OuterHtml ] [
    pageLink $"/request/{reqId}/full" [ btnClass; _title "View Full Request" ] [ icon "description" ]
    match isAnswered with
    | true  -> ()
    | false -> pageLink $"/request/{reqId}/edit" [ btnClass; _title "Edit Request" ] [ icon "edit" ]
    match true with
    | _ when isSnoozed -> restoreBtn "cancel-snooze" "Cancel Snooze"
    | _ when isPending -> restoreBtn "show"          "Show Now"
    | _ -> ()
    p [ _class "request-text mb-0" ] [
      str req.text
      match isSnoozed || isPending || isAnswered with
      | true ->
          br []
          small [ _class "text-muted" ] [
            match () with
            | _ when isSnoozed   -> [ str "Snooze expires ";       relativeDate req.snoozedUntil now ]
            | _ when isPending   -> [ str "Request appears next "; relativeDate req.showAfter    now ]
            | _ (* isAnswered *) -> [ str "Answered ";             relativeDate req.asOf         now ]
            |> em []
            ]
      | false -> ()
      ]
    ]

/// Create a list of requests
let reqList now reqs =
  reqs
  |> List.map (reqListItem now)
  |> div [ _class "list-group" ]

/// View for Active Requests page
let active now reqs = article [ _class "container mt-3" ] [
  h2 [ _class "pb-3" ] [ str "Active Requests" ]
  match reqs |> List.isEmpty with
  | true ->
      noResults "No Active Requests" "/journal" "Return to your journal"
        [ str "Your prayer journal has no active requests" ]
  | false -> reqList now reqs
  ]

/// View for Answered Requests page
let answered now reqs = article [ _class "container mt-3" ] [
  h2 [ _class "pb-3" ] [ str "Answered Requests" ]
  match reqs |> List.isEmpty with
  | true ->
      noResults "No Active Requests" "/journal" "Return to your journal" [
        rawText "Your prayer journal has no answered requests; once you have marked one as “Answered”, "
        str "it will appear here"
        ]
  | false -> reqList now reqs
  ]

/// View for Snoozed Requests page
let snoozed now reqs = article [ _class "container mt-3" ] [
  h2 [ _class "pb-3" ] [ str "Snoozed Requests" ]
  reqList now reqs
  ]

/// View for Full Request page
let full (clock : IClock) (req : Request) =
  let now = clock.GetCurrentInstant ()
  let answered =
    req.history
    |> List.filter RequestAction.isAnswered
    |> List.tryHead
    |> Option.map (fun x -> x.asOf)
  let prayed = (req.history |> List.filter RequestAction.isPrayed |> List.length).ToString "N0"
  let daysOpen =
    let asOf = defaultArg answered now
    ((asOf - (req.history |> List.filter RequestAction.isCreated |> List.head).asOf).TotalDays |> int).ToString "N0"
  let lastText =
    req.history
    |> List.filter (fun h -> Option.isSome h.text)
    |> List.sortByDescending (fun h -> h.asOf)
    |> List.map (fun h -> Option.get h.text)
    |> List.head
  // The history log including notes (and excluding the final entry for answered requests)
  let log =
    let toDisp (h : History) = {| asOf = h.asOf; text = h.text; status = RequestAction.toString h.status |}
    let all =
      req.notes
      |> List.map (fun n -> {| asOf = n.asOf; text = Some n.notes; status = "Notes" |})
      |> List.append (req.history |> List.map toDisp)
      |> List.sortByDescending (fun it -> it.asOf)
    // Skip the first entry for answered requests; that info is already displayed
    match answered with Some _ -> all |> List.skip 1 | None -> all
  article [ _class "container mt-3" ] [
    div [_class "card" ] [
      h5 [ _class "card-header" ] [ str "Full Prayer Request" ]
      div [ _class "card-body" ] [
        h6 [ _class "card-subtitle text-muted mb-2"] [
          match answered with
          | Some date ->
              str "Answered "
              date.ToDateTimeOffset().ToString ("D", null) |> str
              str " ("
              relativeDate date now
              rawText ") • "
          | None -> ()
          sprintf "Prayed %s times • Open %s days" prayed daysOpen |> rawText
          ]
        p [ _class "card-text" ] [ str lastText ]
        ]
      log
      |> List.map (fun it -> li [ _class "list-group-item" ] [
        p [ _class "m-0" ] [
          str it.status
          rawText "  "
          small [] [ em [] [ it.asOf.ToDateTimeOffset().ToString ("D", null) |> str ] ]
          ]
        match it.text with
        | Some txt -> p [ _class "mt-2 mb-0" ] [ str txt ]
        | None -> ()
      ])
      |> ul [ _class "list-group list-group-flush" ]
      ]
    ]

/// View for the edit request component
let edit (req : JournalRequest) returnTo isNew =
  let cancelLink =
    match returnTo with
    | "active"          -> "/requests/active"
    | "snoozed"         -> "/requests/snoozed"
    | _ (* "journal" *) -> "/journal"
  article [ _class "container" ] [
    h2 [ _class "pb-3" ] [ (match isNew with true -> "Add" | false -> "Edit") |> strf "%s Prayer Request" ]
    form [
      _hxBoost
      _hxTarget "#top"
      _hxPushUrl
      "/request" |> match isNew with true -> _hxPost | false -> _hxPatch
      ] [
      input [
        _type  "hidden"
        _name  "requestId"
        _value (match isNew with true -> "new" | false -> RequestId.toString req.requestId)
        ]
      input [ _type "hidden"; _name "returnTo"; _value returnTo ]
      div [ _class "form-floating pb-3" ] [
        textarea [
          _id          "requestText"
          _name        "requestText"
          _class       "form-control"
          _style       "min-height: 8rem;"
          _placeholder "Enter the text of the request"
          _autofocus;  _required
          ] [ str req.text ]
        label [ _for "requestText" ] [ str "Prayer Request" ]
        ]
      br []
      match isNew with
      | true -> ()
      | false ->
          div [ _class "pb-3" ] [
            label [] [ str "Also Mark As" ]
            br []
            div [ _class "form-check form-check-inline" ] [
              input [ _type "radio"; _class "form-check-input"; _id "sU"; _name "status"; _value "Updated"; _checked ]
              label [ _for "sU" ] [ str "Updated" ]
              ]
            div [ _class "form-check form-check-inline" ] [
              input [ _type "radio"; _class "form-check-input"; _id "sP"; _name "status"; _value "Prayed" ]
              label [ _for "sP" ] [ str "Prayed" ]
              ]
            div [ _class "form-check form-check-inline" ] [
              input [ _type "radio"; _class "form-check-input"; _id "sA"; _name "status"; _value "Answered" ]
              label [ _for "sA" ] [ str "Answered" ]
              ]
            ]
      div [ _class "row" ] [
        div [ _class "col-12 offset-md-2 col-md-8 offset-lg-3 col-lg-6" ] [
          p [] [
            strong [] [ rawText "Recurrence   " ]
            em [ _class "text-muted" ] [ rawText "After prayer, request reappears…" ]
            ]
          div [ _class "d-flex flex-row flex-wrap justify-content-center align-items-center" ] [
            div [ _class "form-check mx-2" ] [
              input [
                _type    "radio"
                _class   "form-check-input"
                _id      "rI"
                _name    "recurType"
                _value   "Immediate"
                _onclick "mpj.edit.toggleRecurrence(event)"
                match req.recurType with Immediate -> _checked | _ -> ()
                ]
              label [ _for "rI" ] [ str "Immediately" ]
              ]
            div [ _class "form-check mx-2"] [
              input [
                _type    "radio"
                _class   "form-check-input"
                _id      "rO"
                _name    "recurType"
                _value   "Other"
                _onclick "mpj.edit.toggleRecurrence(event)"
                match req.recurType with Immediate -> () | _ -> _checked
                ]
              label [ _for "rO" ] [ rawText "Every…" ]
              ]
            div [ _class "form-floating mx-2"] [
              input [
                _type        "number"
                _class       "form-control"
                _id          "recurCount"
                _name        "recurCount"
                _placeholder "0"
                _value       (string req.recurCount)
                _style       "width:6rem;"
                _required
                match req.recurType with Immediate -> _disabled | _ -> ()
                ]
              label [ _for "recurCount" ] [ str "Count" ]
              ]
            div [ _class "form-floating mx-2" ] [
              select [
                _class    "form-control"
                _id       "recurInterval"
                _name     "recurInterval"
                _style    "width:6rem;"
                _required
                match req.recurType with Immediate -> _disabled | _ -> ()
                ] [
                option [ _value "Hours"; match req.recurType with Hours -> _selected | _ -> () ] [ str "hours" ]
                option [ _value "Days";  match req.recurType with Days  -> _selected | _ -> () ] [ str "days" ]
                option [ _value "Weeks"; match req.recurType with Weeks -> _selected | _ -> () ] [ str "weeks" ]
                ]
              label [ _form "recurInterval" ] [ str "Interval" ]
              ]
            ]
          ]
        ]
      div [ _class "text-end pt-3" ] [
        button [ _class "btn btn-primary me-2"; _type "submit" ] [ icon "save"; str " Save" ]
        pageLink cancelLink [ _class "btn btn-secondary ms-2" ] [ icon "arrow_back"; str " Cancel" ]
        ]
      ]
    ]

/// Display a list of notes for a request
let notes now notes =
  let toItem (note : Note) =
    p [] [ small [ _class "text-muted" ] [ relativeDate note.asOf now ]; br []; str note.notes ]
  [ p [ _class "text-center" ] [ strong [] [ str "Prior Notes for This Request" ] ]
    match notes with
    | [] -> p [ _class "text-center text-muted" ] [ str "There are no prior notes for this request" ]
    | _  -> yield! notes |> List.map toItem
    ]