open Batteries
open Cmdliner

type copts = { account: string }

let id copts =
  let id' =
    try%lwt
      let%lwt id = Mastocaml.id_of copts.account in
      Lwt_io.printl id
    with
    | Failure m -> Lwt_io.eprintl m
  in
  Lwt_main.run id'

let followers copts =
  let followers' =
    try%lwt
      let%lwt followers = Mastocaml.followers_of copts.account in
      let csv_elements = Array.of_list @@ Mastocaml.(follower_header :: List.map follower_to_row followers) in
      Csv_lwt.(print @@ Csv.of_array csv_elements)
    with
    | Failure m -> Lwt_io.eprintl m
    in
  Lwt_main.run followers'

let test_domain_block copts domain =
  (* there's no Csv_lwt.print_readable so we're doing this cheeseball style and hoping it doesn't blow up *)
  let blocked = Lwt_main.run @@ Mastocaml.test_domain_block copts.account domain in
  let csv_elements = Array.of_list @@ Mastocaml.(blocked_header :: List.map blocked_follower_to_row blocked) in
  Csv.(print_readable @@ of_array csv_elements)

let post copts cw in_reply_to status =
  let status' = String.join " " status in
  let post' =
    try%lwt
      let%lwt response = Mastocaml.status_to copts.account ?cw ?in_reply_to status' in
      Lwt_io.printl Ezjsonm.(find response ["url"] |> get_string)
    with
    | Failure m -> Lwt_io.eprintl m
  in
  Lwt_main.run post'

open Cmdliner

(* Help sections common to all commands *)

let help_secs = [
 `S Manpage.s_common_options;
 `P "These options are common to all commands.";
 `S "MORE HELP";
 `P "Use $(mname) $(i,COMMAND) --help for help on a single command.";
 `S Manpage.s_files;
 `P "Account tokens are retrieved from $(b,\\$XDG_CONFIG_HOME)/mastocaml/$(i,ACCOUNT), which should contain a single line with the token.";
 `S Manpage.s_bugs; `P "Check bug reports at https://fossil.se30.xyz/mastocaml";]

(* Options common to all commands *)

let copts account = { account }
let copts_t =
  let docs = Manpage.s_common_options in
  let account =
    let doc = "Name the account to use." in
    Arg.(required & pos 0 (some string) None & info [] ~docv:"ACCT" ~docs ~doc)
  in
  Term.(const copts $ account)

let sdocs = Manpage.s_common_options

let id_cmd =
  let doc = "verify credentials and return the user's id" in
  let info = Cmd.info "id" ~doc ~sdocs in
  Cmd.v info Term.(const id $ copts_t)

let followers_cmd =
  let doc = "show followers in CSV format" in
  let info = Cmd.info "followers" ~doc ~sdocs in
  Cmd.v info Term.(const followers $ copts_t)

let post_cmd =
  let doc = "make a post" in
  let info = Cmd.info "post" ~doc ~sdocs in
  let cw = Arg.(value & opt (some' string) None & info ["c"; "cw"] ~docv:"WARNING" ~doc:"Set the content warning field") in
  let in_reply_to = Arg.(value & opt (some' string) None & info ["r"; "in-reply-to"] ~docv:"STATUS" ~doc:"Reply to this status") in
  let status = Arg.(non_empty & pos_right 0 string [] & info [] ~docv:"TEXT" ~doc:"The status to post") in
  Cmd.v info Term.(const post $ copts_t $ cw $ in_reply_to $ status)

let test_domain_block_cmd =
  let doc = "show which followers you would lose by blocking a given domain" in
  let info = Cmd.info "test_domain_block" ~doc ~sdocs in
  let blocked = Arg.(required & pos 1 (some string) None & info [] ~docv:"BLOCKED" ~doc:"Name the domain to block") in
  Cmd.v info Term.(const test_domain_block $ copts_t $ blocked)

let main_cmd =
  let doc = "a mastodon tool" in
  let man = help_secs in
  let info = Cmd.info "m" ~version:"0.1" ~doc ~sdocs ~man in
  let default = Term.(ret (const (fun _ -> `Help (`Pager, None)) $ copts_t)) in
  Cmd.group info ~default [id_cmd; post_cmd; followers_cmd; test_domain_block_cmd;]

let () = exit @@ (Cmd.eval main_cmd)
