<script setup lang="ts">
import gsap from "gsap";

const { onRender } = useScreen();
const store = useSettingsStore();
const { assets } = useAssets();

type NotificationData = {
  image: AtlasImage;
  title: string;
  description: string;
};

const menuYOffset = ref(0);
const submenuYOffset = ref(0);
const menuNotificationVisible = ref(false);
const submenuNotificationVisible = ref(false);
const menuNotificationSnapshot = ref<NotificationData | null>(null);
const submenuNotificationSnapshot = ref<NotificationData | null>(null);

const visibleMenuNotification = computed(() =>
  menuNotificationVisible.value
    ? menuNotification.value
    : menuNotificationSnapshot.value,
);
const visibleSubmenuNotification = computed(() =>
  submenuNotificationVisible.value
    ? submenuNotification.value
    : submenuNotificationSnapshot.value,
);

const renderNotification = (
  ctx: CanvasRenderingContext2D,
  image: AtlasImage,
  title: string,
  description: string,
) => {
  assets.images.settings.topScreen.notification.draw(ctx, 0, 0);
  image.draw(ctx, 2, 2);

  ctx.font = "10px NDS10";
  ctx.fillStyle = "#282828";
  ctx.fillText(title, 52, 13);

  ctx.fillStyle = "#fbfbfb";
  const lines = description.split("\n");
  const textY = lines.length === 1 ? 36 : 28;
  for (let i = 0; i < lines.length; i += 1) {
    ctx.fillText(lines[i]!, 52, textY + 14 * i);
  }
};

const mainNotification = computed(() => ({
  image: assets.images.settings.topScreen.settings,
  title: $t("settings.title"),
  description: $t("settings.description"),
}));

const IMAGES_MAP: Record<string, AtlasImage> = {
  options: assets.images.settings.topScreen.options.options,
  optionsRenderingMode: assets.images.settings.topScreen.options.renderingMode,
  optionsLanguage: assets.images.settings.topScreen.options.language,
  options2048: assets.images.settings.topScreen.options._2048,

  clock: assets.images.settings.topScreen.clock.clock,
  clockTime: assets.images.settings.topScreen.clock.time,
  clockDate: assets.images.settings.topScreen.clock.date,
  clockAchievements: assets.images.settings.topScreen.clock.achievements,

  user: assets.images.settings.topScreen.user.user,
  userUserName: assets.images.settings.topScreen.user.userName,
  userBirthday: assets.images.settings.topScreen.user.birthday,
  userSnake: assets.images.settings.topScreen.user.snake,
  userColor: assets.images.settings.topScreen.user.color,

  touchScreen: assets.images.settings.topScreen.touchScreen.touchScreen,
  touchScreenTapTap: assets.images.settings.topScreen.touchScreen.touchScreen,
};

const menuNotification = computed(() => {
  if (!store.currentMenu || !store.menuExpanded) return null;

  return {
    image: IMAGES_MAP[store.currentMenu]!,
    title: $t(`settings.${store.currentMenu}.title`),
    description: $t(`settings.${store.currentMenu}.description`),
  };
});

const submenuNotification = computed(() => {
  if (!store.currentSubMenu) return null;

  const image = IMAGES_MAP[store.currentSubMenu];
  if (!image) return null;

  const menuMatch = store.currentSubMenu.match(
    /^(options|clock|user|touchScreen)(.+)$/,
  );
  if (!menuMatch) return null;

  const [, menu, submenu] = menuMatch;
  const submenuKey = submenu!.charAt(0).toLowerCase() + submenu!.slice(1);

  return {
    image,
    title: $t(`settings.${menu}.${submenuKey}.title`),
    description: $t(`settings.${menu}.${submenuKey}.description`),
  };
});

const animateNotification = (
  curr: NotificationData | null,
  prev: NotificationData | null,
  visibleFlag: Ref<boolean>,
  snapshotRef: Ref<NotificationData | null>,
  offsetRef: Ref<number>,
) => {
  if (prev !== null && curr === null) {
    snapshotRef.value = prev;
    visibleFlag.value = false;
    store.animatingNotification = true;
    gsap.fromTo(
      offsetRef,
      { value: 0 },
      {
        value: 48,
        duration: 0.2,
        ease: "none",
        onComplete: () => {
          snapshotRef.value = null;
          setTimeout(() => {
            store.animatingNotification = false;
          }, 50);
        },
      },
    );
  } else if (prev === null && curr !== null) {
    snapshotRef.value = null;
    visibleFlag.value = true;
    store.animatingNotification = true;
    gsap.fromTo(
      offsetRef,
      { value: 48 },
      {
        value: 0,
        duration: 0.2,
        ease: "none",
        onComplete: () => {
          setTimeout(() => {
            store.animatingNotification = false;
          }, 50);
        },
      },
    );
  }
};

watch(menuNotification, (curr, prev) => {
  animateNotification(
    curr,
    prev,
    menuNotificationVisible,
    menuNotificationSnapshot,
    menuYOffset,
  );
});

watch(submenuNotification, (curr, prev) => {
  animateNotification(
    curr,
    prev,
    submenuNotificationVisible,
    submenuNotificationSnapshot,
    submenuYOffset,
  );
});

onRender((ctx) => {
  const submenuY = 144 + submenuYOffset.value;
  const menuY = visibleSubmenuNotification.value
    ? Math.min(144, submenuY - 16) + menuYOffset.value
    : 144 + menuYOffset.value;
  const nextY = visibleMenuNotification.value
    ? menuY
    : visibleSubmenuNotification.value
      ? submenuY
      : null;
  const mainY =
    nextY !== null
      ? Math.min(144, nextY - 16) + store.notificationYOffset
      : 144 + store.notificationYOffset;

  ctx.translate(0, mainY);
  renderNotification(
    ctx,
    mainNotification.value.image,
    mainNotification.value.title,
    mainNotification.value.description,
  );

  if (visibleMenuNotification.value) {
    ctx.translate(0, menuY - mainY);
    renderNotification(
      ctx,
      visibleMenuNotification.value.image,
      visibleMenuNotification.value.title,
      visibleMenuNotification.value.description,
    );
  }

  if (visibleSubmenuNotification.value) {
    const prevY = visibleMenuNotification.value ? menuY : mainY;
    ctx.translate(0, submenuY - prevY);
    renderNotification(
      ctx,
      visibleSubmenuNotification.value.image,
      visibleSubmenuNotification.value.title,
      visibleSubmenuNotification.value.description,
    );
  }
});

defineOptions({
  render: () => null,
});
</script>
