(*
 *    _  _   ____                         _  
 *  _| || |_/ ___|  ___ _ __  _ __   ___ | | 
 * |_  ..  _\___ \ / _ \ '_ \| '_ \ / _ \| | 
 * |_      _|___) |  __/ |_) | |_) | (_) |_| 
 *   |_||_| |____/ \___| .__/| .__/ \___/(_) 
 *                     |_|   |_|             
 *
 * Personal Social Web.
 *
 * 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 equals_string = Assrt.equals_string
let equals_int = Assrt.equals_int

open Seppo_lib
open Storage

let test_dir_of_ix () =
  Logr.info (fun m -> m "%s.%s" "storage_test" "test_dir_of_ix");
  let a,b = "app/var/db/o/p/23.s" |> Page.of_fn |> Option.get in
  a |> equals_string __LOC__ "o/p";
  b |> equals_int __LOC__ 23;
  let a,_ = "app/var/db/o/t/foo/23.s" |> Page.of_fn |> Option.get in
  a |> equals_string __LOC__ "o/t/foo";
  ()

let test_tuple () =
  Logr.info (fun m -> m "storage_test.test_tuple");
  Logr.info (fun m -> m "%s.%s" "storage_test" "test_tuple");
  (23,42) |> TwoPad10.to_string |> equals_string __LOC__ "(10:0x0000001710:0x0000002a)";
  (0x3fff_ffff,42) |> TwoPad10.to_string |> equals_string __LOC__ "(10:0x3fffffff10:0x0000002a)";
  let (a,b) = "(10:000000002310:0000000042)"
              |> Csexp.parse_string_many
              |> Result.value ~default:[]
              |> TwoPad10.decode_many
              |> List.hd in
  a |> equals_int __LOC__ 23;
  b |> equals_int __LOC__ 42;
  assert true

(*
let test_json () =
  let minify = false in
  let base = Uri.of_string "https://example.com/su/" in
  let item = Rfc4287_test.mk_sample () in
  item |> As2.Note.mk_note_json ~base
  |> As2.Note.mk_create_json ~base item
  |> Ezjsonm.to_string ~minify
  |> eq_s __LOC__ {|{
  "type": "Create",
  "id": "https://example.com/su/o/p-12/#23/Create",
  "actor": "https://example.com/su/activitypub/",
  "published": "2023-02-11T11:07:23+01:00",
  "to": [
    "https://www.w3.org/ns/activitystreams#Public"
  ],
  "cc": [
    "https://example.com/su/activitypub/followers/"
  ],
  "object": {
    "type": "Note",
    "id": "o/p-12/#23",
    "actor": "activitypub/",
    "to": [
      "https://www.w3.org/ns/activitystreams#Public"
    ],
    "cc": [
      "activitypub/followers/"
    ],
    "mediaType": "text/plain; charset=utf8",
    "content": "I am happy to announce the premiere release of #Seppo!, Personal #Social #Media under funding of NLnet.nl.\n\nFind it at https://Seppo.Social/downloads/\n\nIt has no notable user facing #ActivityPub features so far, but\n\n- easy setup of instance & account,\n- #webfinger discoverability (from e.g. mastodon search),\n- a welcoming, long-term reliable website.\n\nI made this embarrassingly limited release to build awareness for low-barrier-entry internet services in general and especially in the field of personal communication as well as letting the #fediverse and #permacomputing communities know.\n\nYour comments are very much appreciated.",
    "sensitive": false,
    "summary": "#Announce Seppo.Social v0.1 and Request for Comments.",
    "published": "2023-02-11T10:07:23Z",
    "tags": [
      {
        "type": "Hashtag",
        "href": "o/t/webfinger/",
        "name": "#webfinger"
      },
      {
        "type": "Hashtag",
        "href": "o/t/Social/",
        "name": "#Social"
      },
      {
        "type": "Hashtag",
        "href": "o/t/Seppo/",
        "name": "#Seppo"
      },
      {
        "type": "Hashtag",
        "href": "o/t/permacomputing/",
        "name": "#permacomputing"
      },
      {
        "type": "Hashtag",
        "href": "o/t/Media/",
        "name": "#Media"
      },
      {
        "type": "Hashtag",
        "href": "o/t/Fediverse/",
        "name": "#Fediverse"
      },
      {
        "type": "Hashtag",
        "href": "o/t/Announce/",
        "name": "#Announce"
      },
      {
        "type": "Hashtag",
        "href": "o/t/ActivityPub/",
        "name": "#ActivityPub"
      }
    ]
  }
}|}
*)

let test_strut () =
  Logr.info (fun m -> m "%s -> %s" __FILE__ "strut");
  let strut' (p0,p1 as s) =
    let r = s |> TwoPad10.strut |> Csexp.to_string in
    Logr.info (fun m -> m "%s.%s %d %s" "" "" (p1-p0) r);
    r
  in
  (0,6)    |> strut' |> equals_string __LOC__  "(0:0:)";

  (0,7)    |> strut' |> equals_string __LOC__  "(0:1:x)";
  (0,8)    |> strut' |> equals_string __LOC__  "(0:2:xx)";
  (0,9)    |> strut' |> equals_string __LOC__  "(0:3:xxx)";

  (0,14)   |> strut' |> equals_string __LOC__  "(0:8:xxxxxxxx)";
  (0,15)   |> strut' |> equals_string __LOC__  "(0:9:xxxxxxxxx)";
  (0,16)   |> strut' |> equals_string __LOC__  "(1:x9:xxxxxxxxx)";
  (0,17)   |> strut' |> equals_string __LOC__  "(0:10:xxxxxxxxxx)";
  (0,18)   |> strut' |> equals_string __LOC__  "(0:11:xxxxxxxxxxx)";

  (0,106)  |> strut' |> equals_string __LOC__  "(0:99:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  (0,107)  |> strut' |> equals_string __LOC__  "(1:x99:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  (0,108)  |> strut' |> equals_string __LOC__ "(0:100:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";

  (0,1007) |> strut' |> equals_string __LOC__ "(0:999:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  (0,1008) |> strut' |> equals_string __LOC__ "(1:x999:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  (0,1009) |> strut' |> equals_string __LOC__ "(0:1000:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  assert true

module Page = struct
  let test_jig () =
    let j = "%-%/index.xml" |> Make.Jig.make in
    let v = "o/p-42/index.xml" |> Make.Jig.cut j |> Option.value ~default:[] in
    (match v with
     | [dir;idx] ->
       dir |> equals_string __LOC__ "o/p";
       idx |> equals_string __LOC__ "42"
     | _ -> failwith __LOC__);
    let dir,idx = "app/var/db/o/p/42.s" |> Storage.Page.of_fn |> Option.get in
    dir |> equals_string __LOC__ "o/p";
    idx |> equals_int __LOC__ 42

  let test_pred_succ () =
    let v = "app/var/db/o/p/42.s" |> Storage.Page.of_fn |> Option.get in
    let dir,idx = v |> Storage.Page.pred in
    dir |> equals_string __LOC__ "o/p";
    idx |> equals_int __LOC__ 41;
    let dir,idx = v |> Storage.Page.succ in
    dir |> equals_string __LOC__ "o/p";
    idx |> equals_int __LOC__ 43

  let test_other_feeds () =
    let _e = match
        Rfc4287.Entry.from_text_plain
          ~published:(Rfc3339.T "1970-01-01T00:00:00Z")
          ~author:Uri.empty
          ~lang:(Rfc4287.Rfc4646 "nl")
          ~uri:Uri.empty
          "title" "content" with
    | Ok o -> o
    | Error e -> failwith e
    in
    let s,i = match _e |> Storage.Page.other_feeds with
      | [x] -> x
      | _ -> failwith "ouch" in
    s |> Assrt.equals_string __LOC__ "o/d/1970-01-01";
    i |> Assrt.equals_int __LOC__ (-3)
end

module TwoPad10 = struct
  let _test_id_to_page_i () =
    Logr.info (fun m -> m "%s" __LOC__);
    let id = "o/p-12/#35" |> Uri.of_string in
    match id |> Storage.TwoPad10.id_to_page_i with
    | Ok ((f,j),i) ->
      f |> Assrt.equals_string __LOC__ "o/p";
      j |> Assrt.equals_int __LOC__ 12;
      i |> Assrt.equals_int __LOC__ 35;
    | _ -> failwith __LOC__

  let _test_from_id' () =
    Logr.info (fun m -> m "%s" __LOC__);
    let _a,_b = "o/p-12/#35"
                |> Uri.of_string
                |> Storage.TwoPad10.from_id ~prefix:"data/"
                |> Result.get_ok in
    ()
end

let () =
  (* Unix.chdir "../../../test/"; *)
  test_dir_of_ix ();
  test_tuple ();
  test_strut ();
  (*  test_json (); *)
  Page.test_jig ();
  Page.test_pred_succ ();
  Page.test_other_feeds ();
  (*
  TwoPad10.test_id_to_page_i ();
  TwoPad10.test_from_id' ();
*)
  assert true
