{-
   Copyright 2020 Eike K. & Contributors

   SPDX-License-Identifier: AGPL-3.0-or-later
-}


module Data.CalEvent exposing
    ( CalEvent
    , everyMonth
    , everyMonthTz
    , fromEvent
    , makeEvent
    )

import Data.TimeZone exposing (TimeZone)
import Util.Maybe


type alias CalEvent =
    { weekday : Maybe String
    , year : String
    , month : String
    , day : String
    , hour : String
    , minute : String
    , timeZone : TimeZone
    }


everyMonth : CalEvent
everyMonth =
    everyMonthTz Data.TimeZone.utc


everyMonthTz : TimeZone -> CalEvent
everyMonthTz tz =
    CalEvent Nothing "*" "*" "01" "00" "00" tz


makeEvent : CalEvent -> String
makeEvent ev =
    let
        datetime =
            ev.year
                ++ "-"
                ++ ev.month
                ++ "-"
                ++ ev.day
                ++ " "
                ++ ev.hour
                ++ ":"
                ++ ev.minute
                ++ " "
                ++ Data.TimeZone.toName ev.timeZone
    in
    case ev.weekday of
        Just wd ->
            wd ++ " " ++ datetime

        Nothing ->
            datetime


fromEvent : String -> Maybe CalEvent
fromEvent str =
    let
        init =
            everyMonth

        parts =
            String.split " " str

        foldChanges : List (CalEvent -> Maybe CalEvent) -> Maybe CalEvent
        foldChanges list =
            List.foldl (\fmc -> \c -> Maybe.andThen fmc c) (Just init) list
    in
    case parts of
        wd :: date :: time :: tz :: [] ->
            foldChanges
                [ fromWeekDays wd
                , fromDate date
                , fromTime time
                , fromTimeZone tz
                ]

        a :: b :: c :: [] ->
            if startsWithWeekday a then
                foldChanges
                    [ fromWeekDays a
                    , fromDate b
                    , fromTime c
                    ]

            else
                foldChanges
                    [ fromDate a
                    , fromTime b
                    , fromTimeZone c
                    ]

        date :: time :: [] ->
            foldChanges
                [ fromDate date
                , fromTime time
                ]

        _ ->
            Nothing


fromDate : String -> CalEvent -> Maybe CalEvent
fromDate date ev =
    let
        parts =
            String.split "-" date
    in
    case parts of
        y :: m :: d :: [] ->
            Just
                { ev
                    | year = y
                    , month = m
                    , day = d
                }

        _ ->
            Nothing


fromTime : String -> CalEvent -> Maybe CalEvent
fromTime time ev =
    case String.split ":" time of
        h :: m :: _ :: [] ->
            Just { ev | hour = h, minute = m }

        h :: m :: [] ->
            Just { ev | hour = h, minute = m }

        _ ->
            Nothing


fromTimeZone : String -> CalEvent -> Maybe CalEvent
fromTimeZone tzStr ev =
    Data.TimeZone.get tzStr
        |> Maybe.map (\tz -> { ev | timeZone = tz })


fromWeekDays : String -> CalEvent -> Maybe CalEvent
fromWeekDays str ce =
    if startsWithWeekday str then
        Just (withWeekday str ce)

    else
        Nothing


withWeekday : String -> CalEvent -> CalEvent
withWeekday wd ev =
    { ev | weekday = Util.Maybe.fromString wd }


weekDays : List String
weekDays =
    [ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" ]


startsWithWeekday : String -> Bool
startsWithWeekday str =
    List.any (\a -> String.startsWith a str) weekDays
