<script setup lang="ts">
import { z } from "zod";
import { LazyApiModal } from "#components";

const qrCode = ref("/default.webp");
const form = useTemplateRef("form");
const baseApiUrl = useBaseApiUrl();

const overlay = useOverlay();
const apiModal = overlay.create(LazyApiModal);

const isQRCodeEmpty = computed(() => qrCode.value === "/default.webp");

const { data: logos } = await useFetch("/api/logos");

const logoItems = computed(
  () =>
    logos.value?.map((name) => ({
      label: name,
      value: name,
      avatar: { src: `/logos/${name}.png`, alt: name },
    })) ?? [],
);

const selectedLogoItem = computed({
  get: () => logoItems.value?.find((i) => i.value === formState.logo),
  set: (item) => {
    formState.logo = item?.value as string | undefined;
  },
});

const formSchema = z
  .object({
    hasLogo: z.boolean(),
    logo: z.string().optional(),
    format: z.enum(IMAGE_FORMATS).default("png"),
    content: z
      .string()
      .optional()
      .transform((v) => v ?? ""),
  })
  .superRefine((data, ctx) => {
    if (!data.content)
      ctx.addIssue({ code: "custom", message: "Required", path: ["content"] });
    if (data.hasLogo && !data.logo)
      ctx.addIssue({ code: "custom", message: "Required", path: ["logo"] });
  });

const formState = reactive<z.input<typeof formSchema>>({
  hasLogo: false,
  logo: undefined,
  format: IMAGE_FORMATS[0],
  content: undefined,
});

const parsedFormState = computed(() => formSchema.safeParse(formState));

watch(formState, async () => {
  await nextTick();
  form.value?.validate({ silent: true });
  updateQRCode();
});

const apiUrl = computed<string>((previous) => {
  if (!parsedFormState.value.success) return previous ?? "";

  const { content, format, hasLogo, logo } = parsedFormState.value.data;
  const params = new URLSearchParams({
    ...(hasLogo && logo && { logo }),
    format,
    content,
  });

  return `${baseApiUrl}?${params}`;
});

const { icon: copyUrlIcon, copy: copyUrl } = useCopyable(apiUrl);

const updateQRCode = async () => {
  if (!parsedFormState.value.success) return;

  const { content, hasLogo, logo, format } = parsedFormState.value.data;
  const logoUrl = hasLogo && logo ? `/logos/${logo}.png` : undefined;
  const canvas = await renderQRCodeToCanvas(content, logoUrl);

  qrCode.value = canvas.toDataURL(format);
};

const downloadQRCode = () => {
  const link = document.createElement("a");
  link.href = qrCode.value;
  link.download = `qrcode.${formState.format}`;

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
};

const {
  copy: copyQRCode,
  icon: copyImageIcon,
  label: copyImageLabel,
} = useCopyable(async () => {
  if (isQRCodeEmpty.value) return;
  if (!parsedFormState.value.success) return;

  const { content, hasLogo, logo } = parsedFormState.value.data;
  const logoUrl = hasLogo && logo ? `/logos/${logo}.png` : undefined;
  const canvas = await renderQRCodeToCanvas(content, logoUrl);

  const qrCode = canvas.toDataURL("png");

  const blob = await (await fetch(qrCode)).blob();
  const item = new ClipboardItem({ "image/png": blob });
  await navigator.clipboard.write([item]);
});
</script>

<template>
  <div class="flex flex-col sm:flex-row justify-between gap-4">
    <img
      :src="qrCode"
      class="w-full max-w-[375px] max-h-[375px] sm:max-w-[315px] sm:max-h-[315px] md:max-w-[375px] md:max-h-[375px] m-auto aspect-square border border-gray-100 dark:border-gray-800"
    >

    <div class="flex-1 flex flex-col justify-center">
      <UForm
        ref="form"
        :schema="formSchema"
        :state="formState"
        :validate-on="['blur']"
        class="space-y-4"
      >
        <UFormField
          label="Username or link"
          name="content"
          :ui="{ error: 'hidden' }"
        >
          <UInput
            v-model="formState.content"
            icon="i-heroicons-user"
            placeholder="Your username or profile link"
            class="w-full"
          />
        </UFormField>

        <UFormField name="logo" :ui="{ error: 'hidden' }">
          <template #label>
            <UCheckbox
              v-model="formState.hasLogo"
              class="mb-1.5"
              label="Logo"
            />
          </template>

          <USelectMenu
            v-model="selectedLogoItem"
            :items="logoItems"
            :disabled="!formState.hasLogo"
            placeholder="Select logo"
            class="w-full"
          >
            <template #leading>
              <NuxtImg
                v-if="selectedLogoItem"
                :src="selectedLogoItem.avatar?.src"
                :alt="selectedLogoItem.label"
                width="16"
                height="16"
                class="dark:invert"
              />
              <UIcon
                v-else
                name="i-heroicons-photo"
                class="size-4 text-dimmed"
              />
            </template>

            <template v-if="selectedLogoItem">{{
              selectedLogoItem.label
            }}</template>

            <template #item-leading="{ item }">
              <NuxtImg
                :src="item.avatar?.src"
                :alt="item.label"
                width="16"
                height="16"
                class="dark:invert"
              />
            </template>
          </USelectMenu>
        </UFormField>

        <UFormField label="Format" name="format">
          <USelectMenu
            v-model="formState.format"
            icon="i-heroicons-document-duplicate"
            :items="unreadonly(IMAGE_FORMATS)"
            placeholder="Select format"
            class="w-full"
          >
            <template #item-label="{ item }">
              {{ upperCase(item) }}
            </template>

            <span v-if="formState.format">{{
              upperCase(formState.format)
            }}</span>
          </USelectMenu>
        </UFormField>

        <UFormField label="API">
          <template #hint>
            <UButton
              size="md"
              color="neutral"
              variant="link"
              icon="i-heroicons-question-mark-circle"
              @click="apiModal.open()"
            />
          </template>

          <UButtonGroup size="sm" class="w-full">
            <UInput
              v-model="apiUrl"
              disabled
              placeholder="Please fill all fields first"
              class="w-full"
            />
            <UButton
              color="neutral"
              variant="subtle"
              :disabled="!apiUrl"
              :icon="copyUrlIcon"
              @click="copyUrl"
            />
          </UButtonGroup>
        </UFormField>

        <div class="flex space-x-4 pt-2">
          <UButton
            class="flex-1"
            block
            :icon="copyImageIcon"
            size="md"
            color="primary"
            variant="solid"
            :label="copyImageLabel"
            :trailing="false"
            :disabled="isQRCodeEmpty"
            @click="copyQRCode"
          />

          <UButton
            class="flex-1"
            block
            icon="i-heroicons-arrow-down-tray"
            size="md"
            color="primary"
            variant="solid"
            label="Download"
            :trailing="false"
            :disabled="isQRCodeEmpty"
            @click="downloadQRCode"
          />
        </div>
      </UForm>
    </div>
  </div>
</template>
