(*
 *    _  _   ____                         _  
 *  _| || |_/ ___|  ___ _ __  _ __   ___ | | 
 * |_  ..  _\___ \ / _ \ '_ \| '_ \ / _ \| | 
 * |_      _|___) |  __/ |_) | |_) | (_) |_| 
 *   |_||_| |____/ \___| .__/| .__/ \___/(_) 
 *                     |_|   |_|             
 *
 * Personal Social Web.
 *
 * test_time.ml
 *
 * Copyright (C) The #Seppo contributors. All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *)

let test_ptime () =
  Assrt.equals_float __LOC__ 1e-3 1.0 1.001;
  (* How would I get the timezone offset for a given Timezone (e.g. local or
     Europe/Amsterdam at a given datetime? *)
  let str0 = "2021-09-28T09:25:00+02:00" in
  match Ptime.of_rfc3339 str0 with
  | Ok (t0, Some tz_s, 25) -> (
      Assrt.equals_string __LOC__ (Ptime.to_rfc3339 ~tz_offset_s:tz_s t0) str0;
      match "2021-09-28T09:37:00+02:00" |> Ptime.of_rfc3339 with
      | Ok (t1, Some 7200, 25) ->
        Ptime.to_float_s t1 -. Ptime.to_float_s t0
        |> Assrt.equals_float __LOC__ 1e-90 (12.0 *. 60.0);
      | _ -> assert false)
  | _ -> assert false

let test_timedesc () =
  (* let tzV = Option.get (Timedesc.Time_zone.local ()) in
     assert ("Europe/Vienna" = Timedesc.Time_zone.name tzV); *)
  let tz = "Europe/Zurich" |> Timedesc.Time_zone.make |> Option.get in
  tz |> Timedesc.Time_zone.name |> Assrt.equals_string __LOC__ "Europe/Zurich";
  let t0 = Timedesc.make_exn ~tz ~year:2021 ~month:9 ~day:21 ~hour:9 ~minute:11 ~second:0 ()
  and t1 = Timedesc.make_exn ~tz ~year:2021 ~month:9 ~day:21 ~hour:9 ~minute:17 ~second:0 ()
  in
  t0 |> Timedesc.to_rfc3339 |> Assrt.equals_string __LOC__ "2021-09-21T09:11:00+02:00";
  t1 |> Timedesc.to_rfc3339 |> Assrt.equals_string __LOC__ "2021-09-21T09:17:00+02:00";
  let dt = Timedesc.to_timestamp_float_s_single t1 -. Timedesc.to_timestamp_float_s_single t0 in
  Assrt.equals_float __LOC__ 1e-90 (6.0 *. 60.0) dt

let test_zoneless_to_zoned () =
  let tz = Timedesc.Time_zone.make_exn "Europe/Zurich"
  and t = Timedesc.Time.make_exn ~hour:1 ~minute:2 ~second:3 ()
  and d0 = Timedesc.Date.of_iso8601_exn "2021-09-28" in
  let zl0 = Timedesc.Zoneless.of_date_and_time d0 t in
  let zo0 = Result.get_ok (Timedesc.Zoneless.to_zoned ~tz zl0) in
  Assrt.equals_string __LOC__ "2021-09-28T01:02:03+02:00" (Timedesc.to_rfc3339 zo0);
  let d1 = Timedesc.Date.of_iso8601_exn "2021-12-28" in
  let zl1 = Timedesc.Zoneless.of_date_and_time d1 t in
  let zo1 = Result.get_ok (Timedesc.Zoneless.to_zoned ~tz zl1) in
  Assrt.equals_string __LOC__ "2021-12-28T01:02:03+01:00" (Timedesc.to_rfc3339 zo1)

let test_zone () =
  let tz_offset_s (tz : Timedesc.Time_zone.t) (t : Ptime.t) : int =
    (match t
           |> Timedesc.Utils.timestamp_of_ptime
           |> Timedesc.of_timestamp_exn ~tz_of_date_time:tz
           |> Timedesc.offset_from_utc with
    | `Single t -> t
    | `Ambiguous (t,_) -> t) 
    |> Timedesc.Timestamp.to_float_s
    |> Int.of_float
  in
  let tz = Timedesc.Time_zone.make_exn "Europe/Amsterdam" in

  let t0,io,i = Ptime.of_rfc3339 "2023-10-17T13:48:37-01:00" |> Result.get_ok in
  io |> Option.get |> Assrt.equals_int __LOC__ (-3600);
  i |> Assrt.equals_int __LOC__ 25;
  t0 |> Ptime.to_rfc3339 |> Assrt.equals_string __LOC__ "2023-10-17T14:48:37-00:00";
  t0 |> Ptime.to_rfc3339 ~tz_offset_s:(tz_offset_s tz t0) |> Assrt.equals_string __LOC__ "2023-10-17T16:48:37+02:00";

  let t0,io,i = Ptime.of_rfc3339 "2023-10-17T13:48:37Z" |> Result.get_ok in
  io |> Option.get |> Assrt.equals_int __LOC__ 0;
  i |> Assrt.equals_int __LOC__ 20;
  t0 |> Ptime.to_rfc3339 |> Assrt.equals_string __LOC__ "2023-10-17T13:48:37-00:00";
  t0 |> Ptime.to_rfc3339 ~tz_offset_s:(tz_offset_s tz t0) |> Assrt.equals_string __LOC__ "2023-10-17T15:48:37+02:00";
  "" |> Assrt.equals_string __LOC__ ""

let () =
  test_ptime ();
  test_timedesc ();
  test_zoneless_to_zoned ();
  test_zone ();
  assert true

