import { describe, it, expect, vi, beforeEach, afterEach, type MockInstance } from 'vitest';
import { listMyUploads, listMyUploadsOrEmpty } from './uploads';

function ok(body: unknown): Response {
    return new Response(JSON.stringify(body), {
        status: 200,
        headers: { 'content-type': 'application/json' }
    });
}

function envelope(status: number, code: string, message: string): Response {
    return new Response(JSON.stringify({ error: { code, message } }), {
        status,
        headers: { 'content-type': 'application/json' }
    });
}

describe('uploads api client', () => {
    let fetchSpy: MockInstance<typeof globalThis.fetch>;

    beforeEach(() => {
        fetchSpy = vi.spyOn(globalThis, 'fetch');
    });
    afterEach(() => {
        vi.restoreAllMocks();
    });

    it('listMyUploads returns the discriminated union of entries', async () => {
        fetchSpy.mockResolvedValueOnce(
            ok({
                items: [
                    {
                        kind: 'manga',
                        manga: {
                            id: 'm1',
                            title: 'A',
                            status: 'ongoing',
                            alt_titles: [],
                            description: null,
                            cover_image_path: null,
                            created_at: '2026-05-17T12:00:00Z',
                            updated_at: '2026-05-17T12:00:00Z'
                        },
                        created_at: '2026-05-17T12:00:00Z'
                    },
                    {
                        kind: 'chapter',
                        manga_id: 'm1',
                        manga_title: 'A',
                        manga_cover_image_path: null,
                        chapter: {
                            id: 'c1',
                            manga_id: 'm1',
                            number: 1,
                            title: null,
                            page_count: 3,
                            created_at: '2026-05-17T13:00:00Z'
                        },
                        created_at: '2026-05-17T13:00:00Z'
                    }
                ],
                page: { limit: 50, offset: 0, total: 2 }
            })
        );
        const r = await listMyUploads();
        expect(r.items[0].kind).toBe('manga');
        expect(r.items[1].kind).toBe('chapter');
        // Discriminant pattern-match (compile-time check via the union).
        if (r.items[1].kind === 'chapter') {
            expect(r.items[1].chapter.number).toBe(1);
        }
    });

    it('listMyUploadsOrEmpty returns empty page on 401', async () => {
        fetchSpy.mockResolvedValueOnce(envelope(401, 'unauthenticated', 'login required'));
        const r = await listMyUploadsOrEmpty();
        expect(r.items).toEqual([]);
    });
});
