import { Page } from '@playwright/test';
import {
    addXtreamPortal,
    channelItemByTitle,
    clickCategoryByNameExact,
    clickFirstGridListCard,
    closeElectronApp,
    defaultXtreamPassword,
    defaultXtreamUsername,
    expectPathname,
    expect,
    goToDashboard,
    launchElectronApp,
    openWorkspaceSection,
    resetMockServers,
    test,
    waitForXtreamWorkspaceReady,
} from './electron-test-fixtures';
import {
    fetchXtreamLiveFixture,
    fetchXtreamSeriesFixture,
    fetchXtreamVodFixture,
    getXtreamTitle,
    pickDistinctTitles,
} from './portal-mock-fixtures';

test.describe('Dashboard Activation', () => {
    test('opens live favorites in the collection route and movies/series in global collection detail views from the dashboard', async ({
        dataDir,
        request,
    }) => {
        await resetMockServers(request, ['xtream']);
        const liveFixture = await fetchXtreamLiveFixture(
            request,
            xtreamCredentials
        );
        const vodFixture = await fetchXtreamVodFixture(
            request,
            xtreamCredentials
        );
        const seriesFixture = await fetchXtreamSeriesFixture(
            request,
            xtreamCredentials
        );
        const [liveTitle] = pickDistinctTitles(
            liveFixture.items,
            getXtreamTitle
        );
        const app = await launchElectronApp(dataDir);

        try {
            await addXtreamPortal(app.mainWindow, {
                name: 'Xtream Dashboard Activation Source',
            });
            await waitForXtreamWorkspaceReady(app.mainWindow);

            await openWorkspaceSection(app.mainWindow, 'Live TV');
            await clickCategoryByNameExact(
                app.mainWindow,
                liveFixture.categoryName
            );
            await toggleFavoriteForChannel(app.mainWindow, liveTitle);

            await app.mainWindow
                .getByRole('link', { name: 'Movies', exact: true })
                .click();
            await clickCategoryByNameExact(
                app.mainWindow,
                vodFixture.categoryName
            );
            const movieTitle = await clickFirstGridListCard(app.mainWindow);
            await addCurrentDetailToFavorites(app.mainWindow);
            await playCurrentDetail(app.mainWindow);
            await goBackFromDetail(app.mainWindow);

            await app.mainWindow
                .getByRole('link', { name: 'Series', exact: true })
                .click();
            await clickCategoryByNameExact(
                app.mainWindow,
                seriesFixture.categoryName
            );
            const seriesTitle = await clickFirstGridListCard(app.mainWindow);
            await playFirstSeriesEpisode(app.mainWindow);

            await goToDashboard(app.mainWindow);

            // v0.22 dashboard: the mixed Global Favorites rail was removed.
            // Favorited live channels are promoted into the favorites-first
            // Live rail; clicking one still opens the Xtream favorites
            // collection with the channel playing.
            await expectDashboardRail(
                app.mainWindow,
                'dashboard-live-recent-rail'
            );
            await dashboardRailCardByTitle(
                app.mainWindow,
                'dashboard-live-recent-rail',
                liveTitle
            ).click();
            await app.mainWindow.waitForURL(
                /\/workspace\/xtreams\/[^/]+\/favorites$/
            );
            await expect(
                app.mainWindow
                    .locator(
                        'app-unified-live-tab .content-container .video-player'
                    )
                    .first()
            ).toBeVisible({ timeout: 20000 });
            await expect(
                channelItemByTitle(app.mainWindow, liveTitle).first()
            ).toHaveClass(/(^|\s)active(\s|$)/);

            await app.mainWindow.goBack();
            await app.mainWindow.waitForURL(/\/workspace\/dashboard$/);

            // Movies and series that were played land in the Continue
            // Watching rail (formerly "recently-watched"); clicking a card
            // opens it inline in the global-recent collection detail view.
            await expectDashboardRail(
                app.mainWindow,
                'dashboard-continue-watching-rail'
            );
            await dashboardRailCardByTitle(
                app.mainWindow,
                'dashboard-continue-watching-rail',
                movieTitle
            ).click();
            await expectInlineCollectionDetail(app.mainWindow, {
                pathname: /\/workspace\/global-recent$/,
                title: movieTitle,
            });

            await app.mainWindow.goBack();
            await expectPathname(app.mainWindow, /\/workspace\/dashboard$/);

            await dashboardRailCardByTitle(
                app.mainWindow,
                'dashboard-continue-watching-rail',
                seriesTitle
            ).click();
            await expectInlineCollectionDetail(app.mainWindow, {
                pathname: /\/workspace\/global-recent$/,
                title: seriesTitle,
            });

            await goBackFromDetail(app.mainWindow);
            await expectPathname(app.mainWindow, /\/workspace\/dashboard$/);
        } finally {
            await closeElectronApp(app);
        }
    });
});

const xtreamCredentials = {
    username: defaultXtreamUsername,
    password: defaultXtreamPassword,
};

async function expectDashboardRail(page: Page, railTestId: string): Promise<void> {
    await expect(page.locator(`[data-test-id="${railTestId}"]`)).toBeVisible({
        timeout: 20000,
    });
}

function dashboardRailCardByTitle(
    page: Page,
    railTestId: string,
    title: string
) {
    return page.locator(`[data-test-id="${railTestId}-card"]`).filter({
        hasText: title,
    }).first();
}

async function goBackFromDetail(page: Page): Promise<void> {
    const backButton = page
        .locator('app-content-hero .hero__back-button')
        .first();

    await expect(backButton).toBeVisible({ timeout: 20000 });
    try {
        await backButton.click({ timeout: 5000 });
    } catch {
        await backButton.evaluate((button: HTMLButtonElement) =>
            button.click()
        );
    }
}

async function addCurrentDetailToFavorites(page: Page): Promise<void> {
    const addButton = page.locator('button.favorite-btn').first();

    await expect(addButton).toBeVisible({ timeout: 20000 });
    await addButton.click();
    await expect(
        page.locator('button.favorite-btn--active').first()
    ).toBeVisible({
        timeout: 20000,
    });
}

async function expectInlineCollectionDetail(
    page: Page,
    params: {
        pathname: RegExp;
        title: string;
    }
): Promise<void> {
    await expectPathname(page, params.pathname);
    await expect(page.locator('app-workspace-context-panel')).toHaveCount(0);
    await expect(page.locator('app-content-hero')).toContainText(params.title);
    await expect(
        page.locator('app-content-hero .hero__back-button').first()
    ).toBeVisible({ timeout: 20000 });
}

async function playCurrentDetail(page: Page): Promise<void> {
    const playButton = page.locator('button.play-btn').first();

    await expect(playButton).toBeVisible({ timeout: 20000 });
    await playButton.click();
}

async function playFirstSeriesEpisode(page: Page): Promise<void> {
    const seasonCard = page.locator('.season-card').first();
    const episodeCard = page
        .locator('.episode-card, .episode-list-item')
        .first();

    await expect
        .poll(
            async () =>
                (await seasonCard.count()) + (await episodeCard.count()),
            { timeout: 20000 }
        )
        .toBeGreaterThan(0);

    if ((await seasonCard.count()) > 0) {
        await seasonCard.scrollIntoViewIfNeeded();
        await expect(seasonCard).toBeVisible({ timeout: 20000 });
        await seasonCard.click();
    }

    await episodeCard.scrollIntoViewIfNeeded();
    await expect(episodeCard).toBeVisible({ timeout: 20000 });
    await episodeCard.click();
}

async function toggleFavoriteForChannel(
    page: Page,
    title: string
): Promise<void> {
    const item = page
        .locator('[data-test-id="channel-item"]')
        .filter({ hasText: title })
        .first();

    await expect(item).toBeVisible({ timeout: 20000 });
    await item.hover();
    await item.locator('.favorite-button').first().click();
    await expect(item.locator('.favorite-button mat-icon').first()).toHaveText(
        /star/
    );
}
