<template>
  <teleport to="body">
    <transition name="bg" @after-enter="onAfterEnter" @after-leave="onAfterLeave">
      <div v-show="show" :style="{ backgroundImage }" class="bg"></div>
    </transition>
  </teleport>
</template>
<style lang="scss" scoped>
.bg {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-size: cover;
  background-position: center;
  z-index: -1000;
  transition:
    opacity 1.5s ease,
    transform 1.5s ease,
    filter 1.5s ease;
}

.bg-enter-from,
.bg-leave-to {
  opacity: 0;
  transform: scale(1.2);
  filter: blur(10px);
}

.bg-enter-to,
.bg-leave-from {
  opacity: 1;
  transform: none;
  filter: none;
}
</style>

<script lang="ts" setup>
import {
  type BackgroundTask,
  type BackgroundURL,
  CancelledError,
  useBackgroundStore,
} from '@/stores/background';
import 'element-plus/theme-chalk/index.css';
import { onMounted, onUnmounted, ref } from 'vue';

const props = defineProps<{
  compId: number;
}>();
const show = ref(false);
const backgroundStore = useBackgroundStore();
const backgroundImage = ref<string>();
let unMounted = false;
let currentTask: BackgroundTask | undefined;
let currentURL: BackgroundURL;
let updateFuture: PromiseWithResolvers<void> | undefined;

async function main() {
  while (!unMounted) {
    currentURL = undefined;
    try {
      currentTask = await backgroundStore.getURL(props.compId);
    } catch (e) {
      console.warn('cancelled(getURL)');
      if (e instanceof CancelledError) {
        break;
      }
      console.error('Error while getting URL:', e);
      continue;
    }
    if (currentTask.url !== undefined) {
      try {
        const resp = await fetch(currentTask.url);
        if (!resp.ok) {
          throw new Error(`Invalid status code: ${resp.status}`);
        }
        currentURL = URL.createObjectURL(await resp.blob());
      } catch (e) {
        console.error(`Error while fetching image ${currentTask.url}:`, e);
        continue;
      }
    }
    updateFuture = Promise.withResolvers<void>();
    if (show.value) {
      show.value = false;
    } else {
      update();
    }
    try {
      await updateFuture.promise;
    } catch (e) {
      if (e instanceof CancelledError) {
        console.warn('cancelled(update)');
        break;
      }
      console.error('Error while updating image:', e);
    }
  }
  console.log('shutdown');
}

onMounted(main);
onUnmounted(() => {
  unMounted = true;
  backgroundStore.unregisterComp(props.compId);
  currentTask?.addFuture.reject(new CancelledError());
  updateFuture?.reject(new CancelledError());
});

async function onAfterEnter() {
  const { options, addFuture } = currentTask!;
  if (options.resolveTiming === 'transitionEnd') {
    addFuture.resolve();
  }
  updateFuture?.resolve();
}

function update() {
  const { options, addFuture } = currentTask!;
  if (currentURL !== undefined) {
    backgroundImage.value = `url("${currentURL}")`;
    show.value = true;
    if (options.resolveTiming === 'transitionStart') {
      addFuture.resolve();
    }
  } else {
    backgroundImage.value = undefined;
    addFuture.resolve();
    updateFuture?.resolve();
  }
}

function onAfterLeave() {
  update();
}
</script>
