<template>
  <v-bottom-sheet
    v-model="modelValue"
    class="mx-2"
    :content-class="['uploads-content', { 'uploads-collapsed': !expanded }]"
    width="400"
    no-click-animation
    persistent
    :scrim="false"
    data-testid="expandBtn"
  >
    <v-sheet class="d-flex flex-column" theme="dark">
      <v-toolbar class="px-4" color="transparent" density="compact" theme="dark">
        <span data-testid="uploadingTitle" v-if="isUploading" class="font-weight-bold"
          >Uploading {{ uploading.length }} items</span
        >
        <span v-else class="font-weight-bold">Uploaded {{ completed.length }} items</span>
        <v-spacer />
        <v-btn
          v-if="uploads.length > 0"
          density="compact"
          :icon="expanded ? 'keyboard_arrow_down' : 'keyboard_arrow_up'"
          variant="text"
          @click="expanded = !expanded"
        />
        <v-btn density="compact" icon="close" variant="text" @click="modelValue = false" />
      </v-toolbar>
      <v-toolbar data-testid="progressToolbar" v-if="isUploading" class="mx-4 progress px-4" density="compact">
        <span class="font-weight-medium">
          {{ estimatedTime > 0 ? `${timeRemaining} remaining` : 'Please wait...' }}
        </span>
        <v-spacer />
        <v-btn data-testid="cancelBtn" density="comfortable" variant="text" @click="cancel">
          <span>{{ t('labels.cancel') }}</span>
        </v-btn>
      </v-toolbar>
      <v-list class="no-hover" density="compact" bg-color="transparent" max-height="300">
        <template v-for="upload in uploads" :key="upload.id">
          <v-list-item>
            <template #prepend>
              <v-icon icon="image" />
            </template>
            <template #append>
              <v-progress-circular
                v-if="upload.status === 'uploading'"
                :model-value="getProgress(upload)"
                :indeterminate="upload.progress === undefined"
                size="24"
              />
              <v-icon v-if="upload.status === 'completed'" icon="filled:check_circle" size="24" />
              <span v-if="upload.status === 'cancelled'" class="font-italic text-subtext">Cancelled</span>
            </template>
            <v-list-item-title class="text-white">
              <span>{{ upload.title }}</span>
            </v-list-item-title>
            <v-list-item-subtitle>
              <span>{{ upload.subtitle }}</span>
            </v-list-item-subtitle>
          </v-list-item>
        </template>
      </v-list>
    </v-sheet>
  </v-bottom-sheet>
</template>

<script setup lang="ts">
import { Upload } from '@3cr/viewer-types-ts';
import { computed, reactive, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { addSeconds, formatDistanceToNowStrict } from 'date-fns';
import { Progress } from '@/models/progress';

interface Props {
  uploads?: Upload[];
}

const props = withDefaults(defineProps<Props>(), {
  uploads: () => []
});

const { t } = useI18n();

const etas = reactive(new Map<string, Progress>());

const modelValue = defineModel<boolean>({ default: false });
const expanded = defineModel<boolean>('expanded', { default: true });

const uploading = computed(() => props.uploads.filter((upload) => upload.status === 'uploading'));
const completed = computed(() => props.uploads.filter((upload) => upload.status === 'completed'));
const isUploading = computed(() => uploading.value.length > 0);

const estimatedTime = computed(() => {
  const progresses = [...etas.values()];
  return Math.round(Math.max(...progresses.map((progress) => progress.value), 0));
});

const timeRemaining = computed(() => {
  return formatDistanceToNowStrict(addSeconds(Date.now(), estimatedTime.value));
});

watch(
  () => props.uploads,
  (uploads) => {
    for (const upload of uploads) {
      if (upload.status === 'uploading' && upload.progress !== undefined) {
        if (!etas.has(upload.id)) {
          etas.set(upload.id, new Progress());
        }
        const eta = etas.get(upload.id);
        eta!.next(upload.progress);
      } else {
        etas.delete(upload.id);
      }
    }
  },
  { deep: true }
);

function getProgress(upload: Upload): number {
  const value = upload.progress ?? 0;
  return value * 100;
}

/* v8 ignore start -- @preserve */
function cancel(): void {
  // TODO: impl
}
/* v8 ignore stop -- @preserve */

defineExpose({ getProgress });
</script>

<style lang="scss">
@use '@/assets/settings' as settings;

.v-bottom-sheet {
  .uploads-content {
    left: unset !important;
    margin: 0 !important;
    border-top-left-radius: settings.$border-radius-root !important;
    border-top-right-radius: settings.$border-radius-root !important;
  }

  .uploads-collapsed {
    top: calc(100% - 48px) !important;
  }
}
</style>

<style scoped lang="scss">
@use '@/assets/palette' as palette;
@use '@/assets/settings' as settings;

.v-sheet {
  background: rgba(31, 31, 55, 0.9) !important;
  backdrop-filter: blur(16px) !important;
  border-top-left-radius: settings.$border-radius-root !important;
  border-top-right-radius: settings.$border-radius-root !important;
}

.v-toolbar.progress {
  background-color: rgba(255, 255, 255, 0.1) !important;
  border-radius: settings.$border-radius-root !important;
  width: auto !important;
}
</style>
