import {
    addStalkerPortal,
    addXtreamPortal,
    closeElectronApp,
    createMutableTextServer,
    deleteSource,
    dropM3uPlaylistOntoWorkspace,
    dragSourceBefore,
    expect,
    expectPlaylistUpdatedToast,
    expectSourceDialogValues,
    getVisibleSourceTitles,
    goToDashboard,
    importM3uPlaylistFromNativeDialog,
    importM3uPlaylistFromUrl,
    launchElectronApp,
    openSources,
    openSourceEditor,
    refreshSource,
    resetMockServers,
    restartElectronApp,
    saveSourceDialog,
    selectSourceSort,
    selectSourceTypeFilter,
    sourceRowByTitle,
    test,
    updateSourceDialog,
    waitForM3uCatalog,
    waitForPortalDebugEvent,
    waitForXtreamCatalog,
    waitForSourceRowIdle,
    writeTemporaryM3uFile,
} from './electron-test-fixtures';

const localSourceFileName = 'alpha-local-source.m3u';
const localSourceDisplayName = 'alpha-local-source';
const urlSourceFileName = 'omega-url-source.m3u';
const xtreamSourceName = 'Charlie Xtream Portal';
const stalkerSourceName = 'Bravo Stalker Portal';
const editableLocalSourceDisplayName = 'editable-local-source';
const deletableLocalSourceDisplayName = 'deletable-local-source';
const refreshLocalSourceDisplayName = 'refresh-local-source';

test.describe('Electron Sources View', () => {
    test('filters and sorts sources, including persisted custom order', async ({
        dataDir,
        request,
    }) => {
        await resetMockServers(request, ['xtream', 'stalker']);
        const localFilePath = writeTemporaryM3uFile(
            dataDir,
            localSourceFileName,
            [
                {
                    groupTitle: 'News',
                    name: 'Alpha Local News',
                    url: 'https://streams.example.test/local-alpha.m3u8',
                },
            ]
        );
        const urlServer = await createMutableTextServer(
            `#EXTM3U
#EXTINF:-1 group-title="Sports",Omega URL Sports
https://streams.example.test/url-omega.m3u8
`,
            {
                contentType: 'application/vnd.apple.mpegurl',
                resourcePath: `/${urlSourceFileName}`,
            }
        );

        const app = await launchElectronApp(dataDir);

        try {
            await importM3uPlaylistFromNativeDialog(app, localFilePath);
            await importM3uPlaylistFromUrl(
                app.mainWindow,
                urlServer.resourceUrl
            );
            await addXtreamPortal(app.mainWindow, {
                name: xtreamSourceName,
            });
            await addStalkerPortal(app.mainWindow, {
                name: stalkerSourceName,
            });
            await openSources(app.mainWindow);

            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toHaveLength(4);

            await selectSourceTypeFilter(app.mainWindow, 'M3U');
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([urlSourceFileName, localSourceDisplayName]);

            await selectSourceTypeFilter(app.mainWindow, 'Xtream');
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([xtreamSourceName]);

            await selectSourceTypeFilter(app.mainWindow, 'Stalker');
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([stalkerSourceName]);

            await selectSourceTypeFilter(app.mainWindow, 'All');

            await selectSourceSort(app.mainWindow, 'Date added (Oldest first)');
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([
                    localSourceDisplayName,
                    urlSourceFileName,
                    xtreamSourceName,
                    stalkerSourceName,
                ]);

            await selectSourceSort(app.mainWindow, 'Name (A-Z)');
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([
                    localSourceDisplayName,
                    stalkerSourceName,
                    xtreamSourceName,
                    urlSourceFileName,
                ]);

            await selectSourceSort(app.mainWindow, 'Name (Z-A)');
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([
                    urlSourceFileName,
                    xtreamSourceName,
                    stalkerSourceName,
                    localSourceDisplayName,
                ]);

            await selectSourceSort(app.mainWindow, 'Date added (Newest first)');
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([
                    stalkerSourceName,
                    xtreamSourceName,
                    urlSourceFileName,
                    localSourceDisplayName,
                ]);

            await selectSourceSort(app.mainWindow, 'Custom order');
            await dragSourceBefore(
                app.mainWindow,
                xtreamSourceName,
                localSourceDisplayName
            );
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([
                    xtreamSourceName,
                    localSourceDisplayName,
                    urlSourceFileName,
                    stalkerSourceName,
                ]);

            await app.mainWindow
                .getByRole('link', { name: 'Dashboard', exact: true })
                .click();
            await openSources(app.mainWindow);
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([
                    xtreamSourceName,
                    localSourceDisplayName,
                    urlSourceFileName,
                    stalkerSourceName,
                ]);

            const restarted = await restartElectronApp(app, dataDir);
            app.electronApp = restarted.electronApp;
            app.mainWindow = restarted.mainWindow;

            await openSources(app.mainWindow);
            await expect
                .poll(() => getVisibleSourceTitles(app.mainWindow))
                .toEqual([
                    xtreamSourceName,
                    localSourceDisplayName,
                    urlSourceFileName,
                    stalkerSourceName,
                ]);
        } finally {
            await closeElectronApp(app);
            await urlServer.close();
        }
    });

    test('edits M3U, Xtream, and Stalker source details and keeps them after restart', async ({
        dataDir,
        request,
    }) => {
        await resetMockServers(request, ['xtream', 'stalker']);
        const localFilePath = writeTemporaryM3uFile(
            dataDir,
            'editable-local-source.m3u',
            [
                {
                    groupTitle: 'Movies',
                    name: 'Editable Local Channel',
                    url: 'https://streams.example.test/editable-local.m3u8',
                },
            ]
        );
        const app = await launchElectronApp(dataDir);

        try {
            await importM3uPlaylistFromNativeDialog(app, localFilePath);
            await addXtreamPortal(app.mainWindow, {
                name: 'Editable Xtream Source',
            });
            await addStalkerPortal(app.mainWindow, {
                name: 'Editable Stalker Source',
            });
            await openSources(app.mainWindow);

            let dialog = await openSourceEditor(
                app.mainWindow,
                editableLocalSourceDisplayName
            );
            await updateSourceDialog(dialog, {
                autoRefresh: true,
                title: 'Edited Local Source',
                userAgent: 'Electron E2E Local/1.0',
            });
            await saveSourceDialog(app.mainWindow, dialog);

            dialog = await openSourceEditor(
                app.mainWindow,
                'Editable Xtream Source'
            );
            await updateSourceDialog(dialog, {
                password: 'pass1',
                serverUrl: 'http://127.0.0.1:3211',
                title: 'Edited Xtream Source',
                username: 'user1',
            });
            await saveSourceDialog(app.mainWindow, dialog);

            dialog = await openSourceEditor(
                app.mainWindow,
                'Editable Stalker Source'
            );
            await updateSourceDialog(dialog, {
                macAddress: '00:1A:79:00:00:99',
                portalUrl: 'http://127.0.0.1:3210/portal.php',
                title: 'Edited Stalker Source',
            });
            await saveSourceDialog(app.mainWindow, dialog);

            dialog = await openSourceEditor(
                app.mainWindow,
                'Edited Local Source'
            );
            await expectSourceDialogValues(dialog, {
                autoRefresh: true,
                title: 'Edited Local Source',
                userAgent: 'Electron E2E Local/1.0',
            });
            await dialog
                .getByRole('button', { name: 'Close', exact: true })
                .click();

            dialog = await openSourceEditor(
                app.mainWindow,
                'Edited Xtream Source'
            );
            await expectSourceDialogValues(dialog, {
                password: 'pass1',
                serverUrl: 'http://127.0.0.1:3211',
                title: 'Edited Xtream Source',
                username: 'user1',
            });
            await dialog
                .getByRole('button', { name: 'Close', exact: true })
                .click();

            dialog = await openSourceEditor(
                app.mainWindow,
                'Edited Stalker Source'
            );
            await expectSourceDialogValues(dialog, {
                macAddress: '00:1A:79:00:00:99',
                portalUrl: 'http://127.0.0.1:3210/portal.php',
                title: 'Edited Stalker Source',
            });
            await dialog
                .getByRole('button', { name: 'Close', exact: true })
                .click();

            const restarted = await restartElectronApp(app, dataDir);
            app.electronApp = restarted.electronApp;
            app.mainWindow = restarted.mainWindow;

            await openSources(app.mainWindow);

            dialog = await openSourceEditor(
                app.mainWindow,
                'Edited Local Source'
            );
            await expectSourceDialogValues(dialog, {
                autoRefresh: true,
                title: 'Edited Local Source',
                userAgent: 'Electron E2E Local/1.0',
            });
            await dialog
                .getByRole('button', { name: 'Close', exact: true })
                .click();

            dialog = await openSourceEditor(
                app.mainWindow,
                'Edited Xtream Source'
            );
            await expectSourceDialogValues(dialog, {
                password: 'pass1',
                serverUrl: 'http://127.0.0.1:3211',
                title: 'Edited Xtream Source',
                username: 'user1',
            });
            await dialog
                .getByRole('button', { name: 'Close', exact: true })
                .click();

            dialog = await openSourceEditor(
                app.mainWindow,
                'Edited Stalker Source'
            );
            await expectSourceDialogValues(dialog, {
                macAddress: '00:1A:79:00:00:99',
                portalUrl: 'http://127.0.0.1:3210/portal.php',
                title: 'Edited Stalker Source',
            });
        } finally {
            await closeElectronApp(app);
        }
    });

    test('deletes M3U, Stalker, and Xtream sources from the sources view', async ({
        dataDir,
        request,
    }) => {
        await resetMockServers(request, ['xtream', 'stalker']);
        const localFilePath = writeTemporaryM3uFile(
            dataDir,
            'deletable-local-source.m3u',
            [
                {
                    groupTitle: 'Live',
                    name: 'Delete Me Local',
                    url: 'https://streams.example.test/delete-local.m3u8',
                },
            ]
        );
        const app = await launchElectronApp(dataDir);

        try {
            await importM3uPlaylistFromNativeDialog(app, localFilePath);
            await addXtreamPortal(app.mainWindow, {
                name: 'Delete Me Xtream',
            });
            await addStalkerPortal(app.mainWindow, {
                name: 'Delete Me Stalker',
            });
            await openSources(app.mainWindow);

            await deleteSource(app.mainWindow, deletableLocalSourceDisplayName);
            await expect(
                sourceRowByTitle(
                    app.mainWindow,
                    deletableLocalSourceDisplayName
                )
            ).toHaveCount(0, {
                timeout: 20000,
            });

            await deleteSource(app.mainWindow, 'Delete Me Stalker');
            await expect(
                sourceRowByTitle(app.mainWindow, 'Delete Me Stalker')
            ).toHaveCount(0, {
                timeout: 20000,
            });

            await deleteSource(app.mainWindow, 'Delete Me Xtream');
            await expect(
                sourceRowByTitle(app.mainWindow, 'Delete Me Xtream')
            ).toHaveCount(0, {
                timeout: 60000,
            });
        } finally {
            await closeElectronApp(app);
        }
    });

    test('refreshes local-file M3U, URL M3U, and Xtream sources from the sources view', async ({
        dataDir,
        request,
    }) => {
        await resetMockServers(request, ['xtream']);
        const localFilePath = writeTemporaryM3uFile(
            dataDir,
            'refresh-local-source.m3u',
            [
                {
                    groupTitle: 'News',
                    name: 'Original Local Channel',
                    url: 'https://streams.example.test/original-local.m3u8',
                },
            ]
        );
        const urlServer = await createMutableTextServer(
            `#EXTM3U
#EXTINF:-1 group-title="News",Original URL Channel
https://streams.example.test/original-url.m3u8
`,
            {
                contentType: 'application/vnd.apple.mpegurl',
                resourcePath: '/refresh-url-source.m3u',
            }
        );
        const app = await launchElectronApp(dataDir);

        try {
            await dropM3uPlaylistOntoWorkspace(
                app.mainWindow,
                localFilePath
            );
            await waitForM3uCatalog(app.mainWindow);
            await expect(
                app.mainWindow.locator(
                    'app-playlist-switcher .trigger-refresh-button'
                )
            ).toBeVisible();

            await goToDashboard(app.mainWindow);
            const sourceCard = app.mainWindow
                .getByTestId('dashboard-recent-sources-rail-card')
                .filter({
                    hasText: refreshLocalSourceDisplayName,
                })
                .first();
            await expect(sourceCard).toBeVisible({ timeout: 20000 });
            await sourceCard.hover();
            await sourceCard
                .getByTestId('dashboard-recent-sources-rail-card-actions')
                .click();
            await expect(
                app.mainWindow.getByRole('menuitem', {
                    name: 'Refresh playlist',
                    exact: true,
                })
            ).toBeVisible();
            await app.mainWindow.keyboard.press('Escape');

            await importM3uPlaylistFromUrl(
                app.mainWindow,
                urlServer.resourceUrl
            );
            await addXtreamPortal(app.mainWindow, {
                name: 'Refresh Xtream Source',
            });
            await openSources(app.mainWindow);
            await expect(
                sourceRowByTitle(
                    app.mainWindow,
                    refreshLocalSourceDisplayName
                )
                    .first()
                    .locator('.refresh-btn')
            ).toBeVisible();

            writeTemporaryM3uFile(dataDir, 'refresh-local-source.m3u', [
                {
                    groupTitle: 'News',
                    name: 'Refreshed Local Channel',
                    url: 'https://streams.example.test/refreshed-local.m3u8',
                },
            ]);
            await refreshSource(app.mainWindow, refreshLocalSourceDisplayName);
            await expectPlaylistUpdatedToast(app.mainWindow);
            await sourceRowByTitle(
                app.mainWindow,
                refreshLocalSourceDisplayName
            )
                .first()
                .click();
            await waitForM3uCatalog(app.mainWindow);
            await expect(
                app.mainWindow.getByTestId('channel-item').filter({
                    hasText: 'Refreshed Local Channel',
                })
            ).toHaveCount(1);
            await openSources(app.mainWindow);

            urlServer.setBody(
                `#EXTM3U
#EXTINF:-1 group-title="News",Refreshed URL Channel
https://streams.example.test/refreshed-url.m3u8
`
            );
            await refreshSource(app.mainWindow, 'refresh-url-source.m3u');
            await expectPlaylistUpdatedToast(app.mainWindow);
            await waitForSourceRowIdle(
                app.mainWindow,
                'refresh-url-source.m3u'
            );
            await sourceRowByTitle(app.mainWindow, 'refresh-url-source.m3u')
                .first()
                .click();
            await waitForM3uCatalog(app.mainWindow);
            await expect(
                app.mainWindow.getByTestId('channel-item').filter({
                    hasText: 'Refreshed URL Channel',
                })
            ).toHaveCount(1);
            await openSources(app.mainWindow);

            await refreshSource(app.mainWindow, 'Refresh Xtream Source', {
                confirm: true,
            });
            await waitForXtreamCatalog(app.mainWindow);
            await waitForPortalDebugEvent(app.mainWindow, {
                operation: 'get_live_categories',
                provider: 'xtream',
                timeoutMs: 30000,
            });
            await openSources(app.mainWindow);
            await waitForSourceRowIdle(app.mainWindow, 'Refresh Xtream Source');
            await expect(
                sourceRowByTitle(app.mainWindow, 'Refresh Xtream Source')
                    .first()
                    .locator('.meta')
            ).toContainText('Updated:');
        } finally {
            await closeElectronApp(app);
            await urlServer.close();
        }
    });
});
