const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];

export type PresignedUrlResponse = {
    upload_url: string;
    key: string;
    uuid: string;
};

export class UploadError extends Error {
    constructor(message: string) {
        super(message);
        this.name = 'UploadError';
    }
}

function getSessionCookie(): string {
    return (
        document.cookie
            .split('; ')
            .find((c) => c.startsWith('XSRF-TOKEN='))
            ?.split('=')[1] ?? ''
    );
}

export async function requestPresignedUrl(
    fileName: string,
    mimeType: string,
    folder?: string,
): Promise<PresignedUrlResponse> {
    const response = await fetch('/api/presigned-url', {
        method: 'POST',
        credentials: 'include',
        headers: {
            'Content-Type': 'application/json',
            'X-Requested-With': 'XMLHttpRequest',
            'X-XSRF-TOKEN': decodeURIComponent(getSessionCookie()),
        },
        body: JSON.stringify({
            file_name: fileName,
            mime_type: mimeType,
            folder,
        }),
    });

    if (!response.ok) {
        const data = await response.json().catch(() => null);

        throw new UploadError(data?.message ?? 'Gagal membuat URL upload.');
    }

    return response.json();
}

export async function uploadToS3(uploadUrl: string, file: File): Promise<void> {
    const response = await fetch(uploadUrl, {
        method: 'PUT',
        body: file,
        headers: {
            'Content-Type': file.type,
        },
    });

    if (!response.ok) {
        throw new UploadError('Gagal mengunggah file ke storage.');
    }
}

export async function uploadFile(file: File, folder?: string): Promise<string> {
    if (!ALLOWED_TYPES.includes(file.type)) {
        throw new UploadError(
            'Tipe file tidak didukung. Hanya JPG, PNG, WebP, dan GIF yang diizinkan.',
        );
    }

    if (file.size > MAX_FILE_SIZE) {
        throw new UploadError('Ukuran file melebihi batas 10MB.');
    }

    const { upload_url, key } = await requestPresignedUrl(
        file.name,
        file.type,
        folder,
    );
    await uploadToS3(upload_url, file);

    return key;
}

export function getTemporaryUrl(key: string, minutes = 60): string {
    return `/api/presigned-url/${encodeURIComponent(key)}?minutes=${minutes}`;
}
