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

const app = useAppStore();
const baseApiUrl = useBaseApiUrl();

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

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

const state = reactive<{
  hasLogo: boolean;
  logo: string | undefined;
  format: ImageFormat;
  content: string | undefined;
}>({
  hasLogo: false,
  logo: undefined,
  format: IMAGE_FORMATS[0],
  content: undefined,
});

const parsedState = computed(() => formSchema.safeParse(state));

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

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

  return `${baseApiUrl}?${params}`;
});
const isValidApiUrl = computed(() => !!apiUrl.value);

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

const openApiModal = () => {
  app.apiModalOpened = true;
};

const updateQRCode = async () => {
  await nextTick();

  if (!parsedState.value.success) return;

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

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

const downloadQRCode = () => {
  const link = document.createElement("a");
  link.href = app.qrCode;
  link.download = `qrcode.${state.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 (!parsedState.value.success) return;
  const { content, hasLogo, logo } = parsedState.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-1 flex flex-col justify-center">
    <UForm
      :schema="formSchema"
      :state="state"
      :validate-on="['blur', 'change', 'input']"
      class="space-y-4"
    >
      <UFormField
        label="Username or link"
        name="content"
        :ui="{ error: 'hidden' }"
      >
        <UInput
          v-model="state.content"
          name="content"
          icon="i-heroicons-user"
          placeholder="Your username or profile link"
          class="w-full"
          @input="updateQRCode"
        />
      </UFormField>

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

        <USelectMenu
          v-model="state.logo"
          name="logo"
          icon="i-heroicons-photo"
          :items="unreadonly(LOGOS)"
          :disabled="!state.hasLogo"
          placeholder="Select logo"
          class="w-full"
          @change="updateQRCode"
        >
          <template #item-label="{ item }">
            {{ capitalize(item) }}
          </template>

          <template v-if="state.logo">{{ capitalize(state.logo) }}</template>
        </USelectMenu>
      </UFormField>

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

          {{ upperCase(state.format) }}
        </USelectMenu>
      </UFormField>

      <UFormField label="API">
        <template #hint>
          <UButton
            size="md"
            color="neutral"
            variant="link"
            icon="i-heroicons-question-mark-circle"
            @click="openApiModal"
          />
        </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="!isValidApiUrl"
            :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>
</template>
