import { Micropub, MicropubChannel, MF2 } from "./micropub_api.js";

const channel_select_radio = document.getElementById("select_channels") as HTMLInputElement;
channel_select_radio.onclick = async () => {
  function populate_channel_list(channels: MicropubChannel[]) {
    (document.getElementById("channels") as HTMLElement).style.display = "block";
    const channel_list = document.getElementById("channels_target") as HTMLElement;
    channel_list.innerHTML = "";
    channels.forEach((channel) => {
      const template = (document.getElementById("channel_selector") as HTMLTemplateElement).content.cloneNode(true) as HTMLElement;
      const input = template.querySelector("input") as HTMLInputElement;
      const label = template.querySelector("label") as HTMLLabelElement;
      input.id = `channel_selector_option_${channel.uid}`
      input.value = channel.uid
      label.htmlFor = input.id
      label.innerHTML = `<a href="${channel.uid}">${channel.name}</a>`

      channel_list.appendChild(template)
    })
  }

  if (micropub == null) {
    throw new Error("need to authenticate first");
  }
  const config = await micropub.config();
  if (config.channels !== undefined) {
    populate_channel_list(config.channels)
  }
}

const no_channel_radio = document.getElementById("no_channel") as HTMLInputElement;
no_channel_radio.onclick = () => {
  (document.getElementById("channels") as HTMLElement).style.display = "none";
  const channel_list = document.getElementById("channels_target") as HTMLElement
  channel_list.innerHTML = "";
}

const main_form = document.getElementById("micropub") as HTMLFormElement;
main_form.onsubmit = async (event) => {
  function construct_body(form: HTMLFormElement): MF2 {
    let content = (form.elements.namedItem("content") as HTMLInputElement).value;
    let name: string | undefined = (form.elements.namedItem("name") as HTMLInputElement).value || undefined;
    let category: string[] = (form.elements.namedItem("category") as HTMLInputElement).value
      .split(",")
      .map(val => val.trim());

    let channel: string[] | undefined = undefined;
    let channel_select = (form.elements.namedItem("channel_select") as HTMLInputElement).value;
    if (channel_select) {
      let channel_selector = form.elements.namedItem("channel");
      if (channel_selector instanceof RadioNodeList) {
        channel = (Array.from(channel_selector) as HTMLInputElement[])
          .map(i => i.checked ? i.value : false)
          .filter(i => i) as string[];
      } else if (channel_selector instanceof HTMLInputElement) {
        channel = [channel_selector.value]
      }
    }
    return {
      type: ["h-entry"],
      properties: {
        content: [content],
        name: name ? [name] : undefined,
        category: category.length ? category : undefined,
        channel: channel ? channel : undefined
      }
    }
  }

  event.preventDefault()
  const mf2 = construct_body(main_form);
  console.log(JSON.stringify(mf2));
  if (micropub == null) {
    throw new Error("need to authenticate first");
  }
  try {
    const location = await micropub.submit(mf2);
    main_form.clear()

    window.open(location, "_blank")
  } catch (e) {
    console.error(e)
    alert(`Error: ${e}`)
    return
  }

}

const indieauth_form = document.getElementById("indieauth") as HTMLFormElement;
indieauth_form.onsubmit = async (event) => {
  event.preventDefault()
  const form = event.target as HTMLFormElement;
  const me = (form.elements.namedItem("me") as HTMLInputElement).value;
  if (me != null) {
    const { discover_endpoints, create_verifier, create_challenge } = await import("./indieauth.js");

    const endpoints = await discover_endpoints(new URL(me));

    if (endpoints != null) {
      localStorage.setItem("micropub_endpoint", endpoints.micropub.toString())
      localStorage.setItem("token_endpoint", endpoints.token_endpoint.toString())
      if (endpoints.revocation_endpoint != null) {
        localStorage.setItem("revocation_endpoint", endpoints.revocation_endpoint.toString())
      }
    } else {
      alert("Your website doesn't support Micropub.")
      return
    }
    (document.getElementById("unauthorized") as HTMLElement).style.display = "none";
    (document.getElementById("authorizing") as HTMLElement).style.display = "block";
    const url = endpoints.authorization_endpoint;
    let params = new URLSearchParams();
    for (const [key, val] of url.searchParams) {
      params.append(key, val)
    }
    params.set("client_id", window.location.href)
    params.set("redirect_uri", window.location.href)
    params.set("response_type", "code")
    params.set("scope", "profile create media")
    params.set("state", "awoo")
    const code_verifier = create_verifier()
    localStorage.setItem("code_verifier", code_verifier)
    params.set("code_challenge", await create_challenge(code_verifier))
    params.set("code_challenge_method", "S256")

    url.search = "?" + params.toString()

    console.log(url)

    window.location.href = url.toString()
  }
}

if (window.location.search != "") {
  (document.getElementById("authorizing") as HTMLElement).style.display = "block";
  const params = new URLSearchParams(window.location.search)
  if (params.has("code") && params.has("state")) {
    const token_endpoint = new URL(localStorage.getItem("token_endpoint")!)
    const state = params.get("state")
    // XXX check state

    const client_id = new URL(window.location.href);
    client_id.search = "";
    const form = new URLSearchParams();
    form.set("grant_type", "authorization_code")
    form.set("code", params.get("code")!)
    form.set("client_id", client_id.toString())
    form.set("redirect_uri", client_id.toString())
    form.set("code_verifier", localStorage.getItem("code_verifier")!)

    const response = await fetch(token_endpoint, {
      method: "POST",
      headers: {
        "Accept": "application/json",
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: form.toString()
    });

    const grant = await response.json();

    // TODO: refresh tokens?
    if ("access_token" in grant) {
      localStorage.setItem("access_token", grant.access_token);
      (document.getElementById("authorizing") as HTMLElement).style.display = "none";
    }
  }
}

let micropub: Micropub | null = null;
const token = localStorage.getItem("access_token")
const endpoint = localStorage.getItem("micropub_endpoint")
if (token == null || endpoint == null) {
  (document.getElementById("unauthorized") as HTMLElement).style.display = "block";
} else {
  // TODO: check token validity
  micropub = new Micropub({ endpoint: new URL(endpoint), token });
  (document.getElementById("authorized") as HTMLElement).style.display = "block";
}