import { Client, CredentialManager } from "@atcute/client";
import { Did } from "@atcute/lexicons";
import {
  createAuthorizationUrl,
  deleteStoredSession,
  getSession,
  OAuthUserAgent,
} from "@atcute/oauth-browser-client";
import { A } from "@solidjs/router";
import { createSignal, For, onMount, Show } from "solid-js";
import { createStore, produce } from "solid-js/store";
import { resolveDidDoc } from "../utils/api.js";
import { ActionMenu, DropdownMenu, MenuProvider, NavMenu } from "./dropdown.jsx";
import { agent, Login, retrieveSession, Sessions, setAgent } from "./login.jsx";
import { Modal } from "./modal.jsx";

export const [sessions, setSessions] = createStore<Sessions>();

const AccountDropdown = (props: { did: Did }) => {
  const removeSession = async (did: Did) => {
    const currentSession = agent()?.sub;
    try {
      const session = await getSession(did, { allowStale: true });
      const agent = new OAuthUserAgent(session);
      await agent.signOut();
    } catch {
      deleteStoredSession(did);
    }
    setSessions(
      produce((accs) => {
        delete accs[did];
      }),
    );
    localStorage.setItem("sessions", JSON.stringify(sessions));
    if (currentSession === did) setAgent(undefined);
  };

  return (
    <MenuProvider>
      <DropdownMenu icon="lucide--ellipsis" buttonClass="rounded-md p-2">
        <NavMenu href={`/at://${props.did}`} label="Go to repo" icon="lucide--user-round" />
        <ActionMenu
          icon="lucide--x"
          label="Remove account"
          onClick={() => removeSession(props.did)}
        />
      </DropdownMenu>
    </MenuProvider>
  );
};

export const AccountManager = () => {
  const [openManager, setOpenManager] = createSignal(false);
  const [avatars, setAvatars] = createStore<Record<Did, string>>();

  onMount(async () => {
    try {
      await retrieveSession();
    } catch {}

    const localSessions = localStorage.getItem("sessions");
    if (localSessions) {
      const storedSessions: Sessions = JSON.parse(localSessions);
      const sessionDids = Object.keys(storedSessions) as Did[];
      sessionDids.forEach(async (did) => {
        const doc = await resolveDidDoc(did);
        const alias = doc.alsoKnownAs?.find((alias) => alias.startsWith("at://"));
        if (alias) {
          setSessions(did, {
            signedIn: storedSessions[did].signedIn,
            handle: alias.replace("at://", ""),
          });
        }
      });
      sessionDids.forEach(async (did) => {
        const avatar = await getAvatar(did);
        if (avatar) setAvatars(did, avatar);
      });
    }
  });

  const resumeSession = async (did: Did) => {
    try {
      localStorage.setItem("lastSignedIn", did);
      await retrieveSession();
    } catch {
      const authUrl = await createAuthorizationUrl({
        scope: import.meta.env.VITE_OAUTH_SCOPE,
        target: { type: "account", identifier: did },
      });

      await new Promise((resolve) => setTimeout(resolve, 250));

      location.assign(authUrl);
    }
  };

  const getAvatar = async (did: Did) => {
    const rpc = new Client({
      handler: new CredentialManager({ service: "https://public.api.bsky.app" }),
    });
    const res = await rpc.get("app.bsky.actor.getProfile", { params: { actor: did } });
    if (res.ok) {
      return res.data.avatar;
    }
    return undefined;
  };

  return (
    <>
      <Modal open={openManager()} onClose={() => setOpenManager(false)}>
        <div class="dark:bg-dark-300 dark:shadow-dark-700 absolute top-18 left-[50%] w-88 -translate-x-1/2 rounded-lg border-[0.5px] border-neutral-300 bg-neutral-50 p-4 shadow-md transition-opacity duration-200 dark:border-neutral-700 starting:opacity-0">
          <div class="mb-2 px-1 font-semibold">
            <span>Manage accounts</span>
          </div>
          <div class="mb-3 max-h-80 overflow-y-auto md:max-h-100">
            <For each={Object.keys(sessions)}>
              {(did) => (
                <div class="flex w-full items-center justify-between">
                  <A
                    href={`/at://${did}`}
                    onClick={() => setOpenManager(false)}
                    class="flex items-center rounded-md p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
                  >
                    <Show
                      when={avatars[did as Did]}
                      fallback={<span class="iconify lucide--user-round m-0.5 size-5"></span>}
                    >
                      <img
                        src={avatars[did as Did].replace("img/avatar/", "img/avatar_thumbnail/")}
                        class="size-6 rounded-full"
                      />
                    </Show>
                  </A>
                  <button
                    class="flex grow items-center justify-between gap-1 truncate rounded-md p-1 hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600"
                    onclick={() => resumeSession(did as Did)}
                  >
                    <span class="truncate">
                      {sessions[did]?.handle ? sessions[did].handle : did}
                    </span>
                    <Show when={did === agent()?.sub && sessions[did].signedIn}>
                      <span class="iconify lucide--check shrink-0 text-green-500 dark:text-green-400"></span>
                    </Show>
                    <Show when={!sessions[did].signedIn}>
                      <span class="iconify lucide--circle-alert shrink-0 text-red-500 dark:text-red-400"></span>
                    </Show>
                  </button>
                  <AccountDropdown did={did as Did} />
                </div>
              )}
            </For>
          </div>
          <Login />
        </div>
      </Modal>
      <button
        onclick={() => setOpenManager(true)}
        class={`flex items-center rounded-lg ${agent() && avatars[agent()!.sub] ? "p-1.25" : "p-1.5"} hover:bg-neutral-200 active:bg-neutral-300 dark:hover:bg-neutral-700 dark:active:bg-neutral-600`}
      >
        {agent() && avatars[agent()!.sub] ?
          <img
            src={avatars[agent()!.sub].replace("img/avatar/", "img/avatar_thumbnail/")}
            class="size-5 rounded-full"
          />
        : <span class="iconify lucide--circle-user-round text-lg"></span>}
      </button>
    </>
  );
};
