import { faToggleOff, faToggleOn } from "@fortawesome/pro-regular-svg-icons";
import { useLocation, useNavigate, useParams } from "@solidjs/router";
import { eq } from "drizzle-orm";
import moment from "moment-timezone";
import createClient from "openapi-fetch";
import {
  For,
  Index,
  createEffect,
  createResource,
  createSignal,
} from "solid-js";
import { createStore } from "solid-js/store";
import { getRequestEvent } from "solid-js/web";
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon";
import Layout from "~/components/Layout";
import db from "~/drizzle";
import { discordTokens } from "~/drizzle/schema";
import { paths } from "~/types/discord";
import "../../styles/pages/config.scss";

if (typeof import.meta.env.VITE_DISCORD_BOT_TOKEN === "undefined")
  throw new Error("No env VITE_DISCORD_BOT_TOKEN found!");

const guessTZ = () => Intl.DateTimeFormat().resolvedOptions().timeZone;

const initialValue = (params: ReturnType<typeof useParams>) => ({
  success: null as boolean | null,
  guild: {
    id: params.guildId,
    name: undefined as string | undefined,
    icon: undefined as string | null | undefined,
    channel: "",
    channels: [] as { id: string; name: string }[],
  },
  tzNames: [guessTZ()],
});

const getPayload = async (
  id: string,
): Promise<
  | { success: false; message: string }
  | (ReturnType<typeof initialValue> & { success: true })
> => {
  "use server";

  const event = getRequestEvent();
  if (!event) return { success: false, message: "No request event!" };

  const pathname = new URL(event.request.url).pathname;
  const { user } = event.nativeEvent.context;
  if (!user) return { success: false, message: "User not logged in!" };

  const tokens = await db.query.discordTokens
    .findFirst({
      where: eq(discordTokens.userId, user.id),
    })
    .execute();
  if (!tokens) return { success: false, message: "No discord access token!" };

  const { GET } = createClient<paths>({
    baseUrl: "https://discord.com/api/v10",
  });
  const guildsRequest = await GET("/users/@me/guilds", {
    headers: { Authorization: `Bearer ${tokens.accessToken}` },
  });
  const channelsRequest = await GET("/guilds/{guild_id}/channels", {
    params: {
      path: {
        guild_id: id,
      },
    },
    headers: { Authorization: `Bot ${import.meta.env.VITE_DISCORD_BOT_TOKEN}` },
  });
  if (guildsRequest.error || channelsRequest.error) {
    console.log(guildsRequest.error, channelsRequest.error, pathname);
    return {
      success: false,
      message: "Error on one of the discord api requests!",
    };
  }

  const guild = guildsRequest.data?.find((e) => e.id === id);

  if (!guild)
    return {
      success: false,
      message: "User is in no such guild with requested id!",
    };
  if (!(parseInt(guild.permissions) & (1 << 5)))
    return {
      success: false,
      message:
        "User is no MANAGE_GUILD permissions on this guild with requested id!",
    };

  const channels: ReturnType<typeof initialValue>["guild"]["channels"] = [];
  channelsRequest.data?.forEach((channel) => {
    if (channel.type !== 0) return;
    channels.push({
      id: channel.id,
      name: channel.name,
    });
  });

  console.log(new URL(event.request.url).pathname, "success");

  return {
    success: true,
    guild: {
      id: guild.id,
      name: guild.name,
      icon: guild.icon,
      channel: "",
      channels,
    },
    tzNames: moment.tz.names(),
  };
};

function config() {
  const params = useParams();
  const navigator = useNavigate();
  const location = useLocation();

  const [timezoneRef, setTimezoneRef] = createSignal<HTMLInputElement>();
  const [timePlanningRef, setTimePlanningRef] =
    createSignal<HTMLInputElement>();
  const [channelRef, setChannelRef] = createSignal<HTMLSelectElement>();
  const [pingableRolesRef, setPingableRolesRef] =
    createSignal<HTMLInputElement>();

  const [timezone, setTimezone] = createSignal(guessTZ());
  const [payload] = createResource(
    params.guildId,
    async (id) => {
      const payload = await getPayload(id).catch((e) => console.warn(e, id));

      if (!payload) {
        console.error(location.pathname, payload);
        return initialValue(params);
      }

      if (!payload.success) {
        console.log(payload);
        console.log(location.pathname, payload.message, "No success");
        navigator("/config", { replace: false });
        return initialValue(params);
      }

      return payload;
    },
    {
      initialValue: initialValue(params),
      deferStream: true,
    },
  );
  const [config, setConfig] = createStore({
    features: {
      timePlanning: {
        enabled: false,
        channelId: "833442323160891452",
        pingableRoles: false,
      },
    },
  });

  createEffect(() => {
    const channelId = payload().guild.channel;
    setConfig("features", "timePlanning", "channelId", channelId);
    const ref = channelRef();
    if (!ref) return;
    ref.value = channelId;
  });
  createEffect(() => {
    const ref = timezoneRef();
    if (!ref) return;
    ref.value = timezone();
  });
  createEffect(() => {
    const ref = timePlanningRef();
    if (!ref) return;
    ref.checked = config.features.timePlanning.enabled;
  });
  createEffect(() => {
    const ref = pingableRolesRef();
    if (!ref) return;
    ref.checked = config.features.timePlanning.pingableRoles;
  });

  return (
    <Layout site="config">
      <h3 class="text-center">Configure li&apos;l Judd in</h3>
      <div>
        <div>
          <div class="flex-row centered">
            <img
              class="guildpfp"
              src={
                payload().guild.icon
                  ? `https://cdn.discordapp.com/icons/${payload().guild.id}/${
                      payload().guild.icon
                    }.webp?size=240`
                  : "https://cdn.discordapp.com/icons/1040502664506646548/bb5a51c4659cf47bdd942bb11e974da7.webp?size=240"
              }
              alt="Server pfp"
            />
            <h1>{payload().guild.name}</h1>
          </div>
        </div>

        <section>
          <h2>Guild</h2>
          <p>General settings for this guild.</p>
          <div class="flex-row">
            <label for="timezone">Timezone for your server:</label>
            <input
              type="text"
              list="timezones"
              id="timezone"
              ref={(e) => setTimezoneRef(e)}
              // disabled={!tzNames().find((e) => e === timezone())}
              onInput={(e) => setTimezone(e.target.value)}
            />

            <datalist id="timezones">
              <Index each={payload().tzNames}>
                {(zone) => <option value={zone()} />}
              </Index>
            </datalist>

            <button
              disabled={guessTZ() === timezone()}
              title={"Detected: " + guessTZ()}
              onClick={() => setTimezone(guessTZ())}
            >
              Auto-detect
            </button>
          </div>
        </section>

        <section>
          <h2>Features</h2>
          <p>Configure the features of the bot</p>
          <label for="timePlanning" class="flex-row">
            <p>Time Planning </p>
            <FontAwesomeIcon
              icon={
                config.features.timePlanning.enabled ? faToggleOn : faToggleOff
              }
              size="xl"
            />
          </label>
          <input
            hidden
            type="checkbox"
            id="timePlanning"
            ref={(e) => setTimePlanningRef(e)}
            onInput={(e) =>
              setConfig("features", "timePlanning", "enabled", e.target.checked)
            }
          />
          <div
            class="sub"
            classList={{ disabled: !config.features.timePlanning.enabled }}
          >
            <div class="flex-row">
              <label>Target channel:</label>
              <select
                ref={(e) => setChannelRef(e)}
                onInput={(e) =>
                  setConfig(
                    "features",
                    "timePlanning",
                    "channelId",
                    e.target.value,
                  )
                }
              >
                <option disabled value="">
                  --Select a Channel--
                </option>
                <For each={payload().guild.channels}>
                  {(channel) => (
                    <option value={channel.id}>{channel.name}</option>
                  )}
                </For>
              </select>
            </div>
            <div class="flex-row">
              <label for="pingableRoles" class="flex-row">
                <p>Enable pingable Roles:</p>
                <FontAwesomeIcon
                  icon={
                    config.features.timePlanning.pingableRoles
                      ? faToggleOn
                      : faToggleOff
                  }
                  size="xl"
                />
              </label>
              <input
                hidden
                type="checkbox"
                id="pingableRoles"
                ref={(e) => setPingableRolesRef(e)}
                onInput={(e) =>
                  setConfig(
                    "features",
                    "timePlanning",
                    "pingableRoles",
                    e.target.checked,
                  )
                }
              />
            </div>
          </div>
        </section>

        <section>
          <button>Apply</button>
          <button onClick={() => navigator("/config")}>Back</button>
        </section>
      </div>
    </Layout>
  );
}

export default config;
