<script setup lang="ts">
import Outline from '@/components/ui/outline/Outline.vue';
import SidebarTrigger from '@/components/ui/sidebar/SidebarTrigger.vue';
import Empty from '@/components/ui/empty/Empty.vue';
import UploadEntry from '@/components/internal/import/uploadentry/UploadEntry.vue';
import EmptyHeader from '@/components/ui/empty/EmptyHeader.vue';
import EmptyMedia from '@/components/ui/empty/EmptyMedia.vue';
import EmptyTitle from '@/components/ui/empty/EmptyTitle.vue';
import EmptyDescription from '@/components/ui/empty/EmptyDescription.vue';

import { MegaphoneOff, Play } from 'lucide-vue-next';
import type { EventSourceListener } from '~/composeables/api/event-source';
import type { StreamProgress200Item } from '~/composeables/api/models';
import { streamProgress } from '~/composeables/api/progress-sse-controller/progress-sse-controller';
import { useCurrentPlaylistStore } from '~/stores/use-current-playlist-store';
import FileUpload from '@/components/ui/file-upload/FileUpload.vue';
import FileUploadGrid from '@/components/ui/file-upload/FileUploadGrid.vue';
import Button from '@/components/ui/button/Button.vue';
import { addLocalTrack } from '~/composeables/api/track-controller/track-controller';

const files = ref<File[]>([]);
const currentPlaylistStore = useCurrentPlaylistStore();
const progressEntries = ref<Map<string, StreamProgress200Item>>(new Map());
let listener: EventSourceListener<StreamProgress200Item> | null = null;

const ongoingUploads = ref<Map<string, { file: File; progress: number }>>(new Map());

const sortedProgressEntries = computed(() => {
    return Array.from(progressEntries.value.values())
        .sort((a, b) => {
            const timeA = a.timestamp || 0;
            const timeB = b.timestamp || 0;
            return timeB - timeA;
        });
});

const unwatch = watch(() => currentPlaylistStore.id, (newId, oldId) => {
    if (newId !== -1 && newId !== oldId) {
        listenImports();
    } else if (newId === -1) {
        stopImports();
    }
}, { immediate: true });

const updateEntryFromProgress = (data: StreamProgress200Item) => {
    if (!data.trackSourceId)
        return;
    progressEntries.value = new Map(progressEntries.value);
    progressEntries.value.set(data.id!.toString(), data);
}

async function listenImports() {
    if (listener) {
        listener.close();
    }
    streamProgress(currentPlaylistStore.id).then(listener => {
        listener.handle(data => {
            updateEntryFromProgress(data);
        })
    }).catch(err => {
        console.error(err);
    })
}

async function handleFileUpload(uploadedFiles: File[]) {
    if (!currentPlaylistStore.id || currentPlaylistStore.id === -1) {
        console.error('No playlist selected');
        return;
    }

    for (const file of uploadedFiles) {
        const uploadId = generateUploadId(file);

        ongoingUploads.value.set(uploadId, { file, progress: 0 });

        try {
            const formData = new FormData();
            formData.append('source', file);

            await addLocalTrack(
                currentPlaylistStore.id,
                { source: file },
                {
                    onUploadProgress: (progressEvent) => {
                        if (progressEvent.total) {
                            const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);
                            ongoingUploads.value.set(uploadId, {
                                file,
                                progress: Math.min(progress, 100)
                            });

                            ongoingUploads.value = new Map(ongoingUploads.value);
                        }
                    }
                }
            );

            ongoingUploads.value.delete(uploadId);
            ongoingUploads.value = new Map(ongoingUploads.value);

            const index = files.value.findIndex(f =>
                f.name === file.name &&
                f.size === file.size &&
                f.lastModified === file.lastModified
            );
            if (index !== -1) {
                files.value.splice(index, 1);
            }

        } catch (error) {
            console.error('Upload failed:', error);
            ongoingUploads.value.delete(uploadId);
            ongoingUploads.value = new Map(ongoingUploads.value);
        }
    }
}

function generateUploadId(file: File): string {
    return `${file.name}-${file.size}-${file.lastModified}-${Date.now()}`;
}

function handleFileChange(changedFiles: File[]) {
    files.value = changedFiles;

    handleFileUpload(changedFiles);
}

function onYoutubeClick(e: MouseEvent) {
    e.stopPropagation();
}

function stopImports() {
    if (listener) {
        listener.close();
        listener = null;
    }
}

onUnmounted(() => {
    stopImports();
    unwatch();
});
</script>

<template>
    <div class="flex-1">
        <NuxtLayout name="default">
            <template #header>
                <Outline side="bottom" padding="dense" class="w-full">
                    <div class="flex gap-8 w-full items-center">
                        <SidebarTrigger :size="5" />
                        <h2 class="scroll-m-20 text-3xl font-semibold tracking-tight transition-colors first:mt-0">
                            Import tracks
                        </h2>
                    </div>
                </Outline>
            </template>
            <div class="w-full flex flex-col p-8">
                <FileUpload v-model="files" class="rounded-lg border border-dashed border-muted"
                    @onChange="handleFileChange" :ongoing-uploads="ongoingUploads">
                    <template #default>
                        <FileUploadGrid />
                    </template>
                    <template #content>
                        <h4 class="z-20 scroll-m-20 text-xl font-semibold tracking-tight">
                            Drag and drop your audio files
                        </h4>
                        <p class="z-20 font-normal text-muted-foreground">
                            or
                        </p>
                        <Button class="z-20" variant="destructive" @click="onYoutubeClick">
                            <Play />
                            From Youtube
                        </Button>
                    </template>
                </FileUpload>
                <div>
                    <h3 class="scroll-m-20 text-2xl font-semibold tracking-tight">
                        Uploaded files
                    </h3>
                    <div class="space-y-2">


                        <UploadEntry v-for="entry in sortedProgressEntries" :key="entry.id" :entry="entry" />

                        <Empty class="border border-dashed"
                            v-if="progressEntries.size === 0 && ongoingUploads.size === 0">
                            <EmptyHeader>
                                <EmptyMedia variant="icon">
                                    <MegaphoneOff />
                                </EmptyMedia>
                                <EmptyTitle>No imports found</EmptyTitle>
                                <EmptyDescription>
                                    Upload any track to see their progress.
                                </EmptyDescription>
                            </EmptyHeader>
                        </Empty>
                    </div>
                </div>
            </div>
        </NuxtLayout>
    </div>
</template>
