(*
 *    _  _   ____                         _  
 *  _| || |_/ ___|  ___ _ __  _ __   ___ | | 
 * |_  ..  _\___ \ / _ \ '_ \| '_ \ / _ \| | 
 * |_      _|___) |  __/ |_) | |_) | (_) |_| 
 *   |_||_| |____/ \___| .__/| .__/ \___/(_) 
 *                     |_|   |_|             
 *
 * Personal Social Web.
 *
 * webfinger_test.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/>.
 *)

open Seppo_lib

let test_uri_from_string () =
  Logr.debug (fun m -> m "%s.%s" "webfinger" "uri_from_string");
  Uri.make ~scheme:Rfc7565.scheme
    ~userinfo:"a:b/c" ~host:"d.e" ()
  |> Uri.to_string
  |> Assrt.equals_string __LOC__ "acct://a:b%2Fc@d.e";
  "mailto:demo@d.seppo.social"
  |> Uri.of_string
  |> Uri.host
  |> Option.value ~default:"-"
  |> Assrt.equals_string __LOC__ "-";

  "acct:ab/c@d.e"
  |> Rfc7565.of_string |> Result.get_ok
  |> Rfc7565.to_string
  |> Assrt.equals_string __LOC__ "acct:ab/c@d.e";
  "acct:ab/c@d.e"
  |> Rfc7565.of_string |> Result.get_ok
  |> Webfinger.well_known_uri
  |> Uri.host
  |> Option.value ~default:"-"
  |> Assrt.equals_string __LOC__ "d.e";
  "acct:ab/c@d.e"
  |> Rfc7565.of_string |> Result.get_ok
  |> Webfinger.well_known_uri
  |> Uri.to_string
  |> Assrt.equals_string __LOC__ "https://d.e/.well-known/webfinger?resource=acct:ab/c@d.e";
  "acct:demo@d.seppo.social"
  |> Rfc7565.of_string |> Result.get_ok
  |> Webfinger.well_known_uri
  |> Uri.host
  |> Option.value ~default:"-"
  |> Assrt.equals_string __LOC__ "d.seppo.social";
  "@a@b.c"
  |> Rfc7565.of_string |> Result.get_ok
  |> Rfc7565.to_string
  |> Assrt.equals_string __LOC__ "acct:a@b.c";
  "a@b.c"
  |> Rfc7565.of_string |> Result.get_ok
  |> Rfc7565.to_string
  |> Assrt.equals_string __LOC__ "acct:a@b.c";
  (*
  "http://a@b.c"
  |> Webfinger.Rfc7565.of_string_
  |> Webfinger.Rfc7565.to_string
  |> Assrt.equals_string __LOC__ "acct:a@b.c"
*)
  ()

let test_handle () =
  Logr.debug (fun m -> m "%s.%s" "webfinger" "handle");
  (match "uh@ah.oh" |> Rfc7565.of_string with
   | Ok acct -> acct |> Rfc7565.to_string |> Assrt.equals_string __LOC__ "acct:uh@ah.oh"
   | Error _ -> failwith __LOC__
  );

  "ok@example.com"
  |> Rfc7565.of_string
  |> Result.get_ok
  |> Rfc7565.to_string
  |> Assrt.equals_string __LOC__ "acct:ok@example.com"

let test_webfinger () =
  Logr.debug (fun m -> m "webfinger");
  Webfinger.jsonm (Auth.Uid "usr", Uri.of_string "scheme://example.com/p/a/t/h/")
  |> Result.get_ok
  |> Ezjsonm.value_to_string ~minify:false
  |> Assrt.equals_string __LOC__
    {|{
  "subject": "acct:usr@example.com",
  "links": [
    {
      "href": "scheme://example.com/p/a/t/h/activitypub/actor.jsa",
      "rel": "self",
      "type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
    },
    {
      "href": "scheme://example.com/p/a/t/h/",
      "rel": "http://webfinger.net/rel/profile-page",
      "type": "text/html"
    },
    {
      "href": "scheme://example.com/p/a/t/h/o/p/",
      "rel": "alternate",
      "type": "application/atom+xml"
    },
    {
      "rel": "http://ostatus.org/schema/1.0/subscribe",
      "template": "scheme://example.com/p/a/t/h/seppo.cgi/activitypub/actor.xml?id={uri}"
    }
  ]
}|};
  assert true

let test_decode () =
  Logr.debug (fun m -> m "webfinger_decode");
  let j = "data/webfinger/gnusocial.json" |> File.in_channel Ezjsonm.value_from_channel in
  let q = As2_vocab.Decode.Webfinger.query_result j |> Result.get_ok in
  q.subject |> Assrt.equals_string __LOC__ "acct:administrator@gnusocial.net";
  As2_vocab.Encode.Webfinger.query_result ~base:Uri.empty q
  |> Ezjsonm.value_to_string ~minify:false
  |> Assrt.equals_string __LOC__ {|{
  "subject": "acct:administrator@gnusocial.net",
  "aliases": [
    "https://gnusocial.net/index.php/user/1",
    "https://gnusocial.net/administrator",
    "https://gnusocial.net/user/1",
    "https://gnusocial.net/index.php/administrator"
  ],
  "links": [
    {
      "href": "https://gnusocial.net/administrator",
      "rel": "http://webfinger.net/rel/profile-page",
      "type": "text/html"
    },
    {
      "rel": "http://ostatus.org/schema/1.0/subscribe",
      "template": "https://gnusocial.net/main/remotefollowsub?profile={uri}"
    },
    {
      "href": "https://gnusocial.net/index.php/user/1",
      "rel": "self",
      "type": "application/activity+json"
    }
  ]
}|};
  let j = "data/webfinger/pleroma.json" |> File.in_channel Ezjsonm.value_from_channel in
  let q = j |> As2_vocab.Decode.Webfinger.query_result |> Result.get_ok in
  q.subject |> Assrt.equals_string __LOC__ "acct:gabek@social.gabekangas.com";
  assert true

let test_sift () =
  Logr.debug (fun m -> m "webfinger_test.test_webfinger_sift");
  let base = Uri.of_string "https://example.com/sub/" in
  let p = Webfinger.make (Auth.Uid "usr", base) in
  p.links
  |> As2_vocab.Types.Webfinger.profile_page
  |> Option.get
  |> Uri.to_string
  |> Assrt.equals_string __LOC__ ".";
  p.links
  |> As2_vocab.Types.Webfinger.self_link
  |> Option.get
  |> Uri.to_string
  |> Assrt.equals_string __LOC__ "activitypub/actor.jsa";
  p
  |> As2_vocab.Encode.Webfinger.query_result ~base
  |> Ezjsonm.value_to_string ~minify:false
  |> Assrt.equals_string __LOC__ {|{
  "subject": "acct:usr@example.com",
  "links": [
    {
      "href": "https://example.com/sub/activitypub/actor.jsa",
      "rel": "self",
      "type": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""
    },
    {
      "href": "https://example.com/sub/",
      "rel": "http://webfinger.net/rel/profile-page",
      "type": "text/html"
    },
    {
      "href": "https://example.com/sub/o/p/",
      "rel": "alternate",
      "type": "application/atom+xml"
    },
    {
      "rel": "http://ostatus.org/schema/1.0/subscribe",
      "template": "https://example.com/sub/seppo.cgi/activitypub/actor.xml?id={uri}"
    }
  ]
}|}

let test_many () =
  let ex = [
    ("@actapopuli@fediverse.blog.json"  ,"https://fediverse.blog/@/actapopuli/");
    ("@administrator@gnusocial.net.json","https://gnusocial.net/index.php/user/1");
    ("@btsavage@threads.net.json"       ,"https://threads.net/ap/users/17841401679436667/");
    ("@dansup@pixelfed.social.json"     ,"https://pixelfed.social/users/dansup");
    ("@demo@seppo.social.json"          ,"https://seppo.social/demo/activitypub/actor.jsa");
    ("@framasoft@mobilizon.fr.json"     ,"https://mobilizon.fr/@framasoft");
    ("@gargron@mastodon.social.json"    ,"https://mastodon.social/users/Gargron");
    ("@Greensky@open.audio.json"        ,"https://open.audio/federation/actors/Greensky");
    ("@kainoa@calckey.social.json"      ,"https://calckey.social/users/9aprgabaeb");
    ("@karolat@stereophonic.space.json" ,"https://stereophonic.space/users/karolat");
    ("@lemmy_support@lemmy.ml.json"     ,"https://lemmy.ml/c/lemmy_support");
    ("@manton@manton.org.json"          ,"https://manton.org/activitypub/manton");
    ("@matt@write.as.json"              ,"https://write.as/api/collections/matt");
    ("@mike@macgirvin.com.json"         ,"https://macgirvin.com/channel/mike");
    ("@peertube@framapiaf.org.json"     ,"https://framapiaf.org/users/peertube");
    ("@syuilo@misskey.io.json"          ,"https://misskey.io/users/7rkrarq81i");
    ("@tobias@friendi.ca.json"          ,"https://friendi.ca/author/tobias/");
    ("atom.json"                        ,"https://example.com/activitypub/");
    ("bonfire.json"                     ,"https://campground.bonfire.cafe/pub/actors/stpaultim");
    ("gnusocial.json"                   ,"https://gnusocial.net/index.php/user/1");
    ("mini.json"                        ,"https://example.com/activitypub/");
    ("misskey.json"                     ,"https://misskey.io/users/7rkrarq81i");
    ("pleroma.json"                     ,"https://social.gabekangas.com/users/gabek");
    ("zap.json"                         ,"https://macgirvin.com/channel/mike");
  ] in
  let dir = "data/webfinger/" in
  dir |> File.fold_dir
    (fun init f ->
       if match f with
         | "@contribute@hubzilla.org.json" -> false
         | f -> f |> St.is_suffix ~affix:".json"
       then (
         let q = (dir ^ f)
                 |> File.in_channel Ezjsonm.value_from_channel
                 |> As2_vocab.Decode.Webfinger.query_result
                 |> Result.get_ok in
         let a = q.links
                 |> As2_vocab.Types.Webfinger.self_link
                 |> Option.get in
         (* Logr.debug (fun m -> m {|%s.%s ("%s","%a");|} "Webfinger" "test_many" f Uri.pp a); *)
         a |> Uri.to_string |> Assrt.equals_string __LOC__ (List.assoc f ex);
         1 + init , true
       ) else
         init , true)
    0
  |> Assrt.equals_int __LOC__ (ex |> List.length)

let () =
  Unix.chdir "../../../test/";
  Printexc.record_backtrace true;
  test_uri_from_string ();
  test_handle ();
  test_webfinger ();
  test_decode ();
  test_sift ();
  test_many ();
  assert true
