defmodule LibraryFees do
  def datetime_from_string(string) do
    case NaiveDateTime.from_iso8601(string) do
      {:ok, naive_date_time} -> naive_date_time
      _ -> :error
    end
  end

  def before_noon?(datetime) do
    datetime.hour < 12
  end

  defp days_to_return(checkout_datetime) do
    if(before_noon?(checkout_datetime), do: 28, else: 29)
  end

  def return_date(checkout_datetime) do
    checkout_datetime
    |> NaiveDateTime.add(days_to_return(checkout_datetime), :day)
    |> NaiveDateTime.to_date()
  end

  def days_late(planned_return_date, actual_return_datetime) do
    actual_return_datetime
    |> NaiveDateTime.to_date()
    |> Date.diff(planned_return_date)
    |> case do
      late_in_days when late_in_days > 0 -> late_in_days
      _late_in_days -> 0
    end
  end

  def monday?(datetime) do
    datetime
    |> NaiveDateTime.to_date()
    |> Date.day_of_week(:monday)
    |> case do
      1 -> true
      _ -> false
    end
  end

  def calculate_late_fee(checkout, return, rate) do
    checkout_date_time = datetime_from_string(checkout)
    actual_return_date_time = datetime_from_string(return)
    planed_return_date_time = return_date(checkout_date_time)

    fee = days_late(planed_return_date_time, actual_return_date_time) * rate

    case monday?(actual_return_date_time) do
      true -> floor(fee * 0.5)
      _ -> fee
    end
  end
end