import { Page, Locator, expect } from '@playwright/test';

async function isVisible(locator: Locator, timeout = 1000): Promise<boolean> {
    return locator.isVisible({ timeout }).catch(() => false);
}

export class MediaCreationProcess {

    readonly page: Page;
    readonly chatInput: Locator;
    readonly welcomePopupBanner: Locator;
    readonly welcomePopup: Locator;
    readonly dontShowAgainCheckbox: Locator;
    readonly receivedMessageBubbles: Locator;
    readonly domainFirstQuestion: Locator;
    readonly mediaNamePrompt: Locator;
    readonly contentUrlPrompt: Locator;
    readonly sourceUrlInput: Locator;
    readonly dialogConfirmButton: Locator;

    constructor(page: Page) {

        this.page = page;

        this.chatInput = page.getByPlaceholder('Ask anything...').first();

        this.welcomePopupBanner = page.locator('#welcome-cards-banner').first();

        // popup container
        this.welcomePopup = page.getByText('Welcome to RoboCorp!').first();

        this.dontShowAgainCheckbox = page.getByRole('checkbox', {
            name: /don't show again/i
        }).first();

        this.receivedMessageBubbles = page.locator('div.group\\/message.bg-green-blue-8');
        this.domainFirstQuestion = page.getByText(
            /Would you like to create a new domain first\?/i
        ).first();
        this.mediaNamePrompt = page.getByText(
            /Please provide the name of your new media/i
        ).first();
        this.contentUrlPrompt = page.getByText(
            /Please provide the content url of your new media/i
        ).first();
        this.sourceUrlInput = page.getByRole('textbox', {
            name: /Policy Source File URL/i
        }).first();
        this.dialogConfirmButton = page
            .locator('#multi_type_input_widget_dialog')
            .getByRole('button', { name: /^Confirm$/i })
            .first();
    }

    async closeWelcomePopupIfVisible() {
        await this.welcomePopup.waitFor({ state: 'visible', timeout: 8000 }).catch(() => null);

        const popupVisible = await this.welcomePopup.isVisible({ timeout: 1000 }).catch(() => false);

        if (popupVisible) {
            if (await this.dontShowAgainCheckbox.isVisible({ timeout: 1000 }).catch(() => false)) {
                await this.dontShowAgainCheckbox.click({ force: true }).catch(() => {});
            }

            const closeCandidates = [
                this.page.locator('#welcome-cards-banner button.absolute').first(),
                this.welcomePopupBanner.locator('button.absolute').first(),
                this.welcomePopupBanner.locator('button').last(),
                this.page.getByRole('button', { name: /close/i }).first(),
            ];

            for (const closeButton of closeCandidates) {
                if (await closeButton.isVisible({ timeout: 1000 }).catch(() => false)) {
                    await closeButton.click({ force: true }).catch(() => {});
                    if (await this.welcomePopup.isVisible({ timeout: 1000 }).catch(() => false)) {
                        await closeButton.evaluate((node) => {
                            (node as HTMLButtonElement).click();
                        }).catch(() => {});
                    }
                    const stillVisible = await this.welcomePopup.isVisible({ timeout: 1500 }).catch(() => false);
                    if (!stillVisible) {
                        return;
                    }
                }
            }

            await this.page.keyboard.press('Escape').catch(() => {});
            const stillVisible = await this.welcomePopup.isVisible({ timeout: 1500 }).catch(() => false);
            if (!stillVisible) {
                return;
            }

            throw new Error('Welcome popup is visible but could not be closed.');
        }
    }

    async startMediaCreation() {
        await this.closeWelcomePopupIfVisible();
        const popupStillVisible = await this.welcomePopup.isVisible({ timeout: 1000 }).catch(() => false);
        expect(popupStillVisible).toBeFalsy();
        await expect(this.chatInput).toBeVisible({ timeout: 30000 });
        await expect(this.chatInput).toBeEditable({ timeout: 30000 });

        await this.chatInput.fill('I want to create a media');
        await this.chatInput.press('Enter');

        const firstPromptDeadline = Date.now() + 90000;
        while (Date.now() < firstPromptDeadline) {
            if (await isVisible(this.domainFirstQuestion, 500) || await isVisible(this.mediaNamePrompt, 500)) {
                break;
            }
        }

        if (await isVisible(this.domainFirstQuestion, 2000)) {
            const skipDomainButton = this.page.getByRole('button', {
                name: /skip|no|without domain|use general knowledge/i
            }).first();

            if (await skipDomainButton.isVisible({ timeout: 3000 }).catch(() => false)) {
                await skipDomainButton.click();
            } else {
                await this.chatInput.fill('No, proceed without creating a domain');
                await this.chatInput.press('Enter');
            }
        }

        await expect(this.mediaNamePrompt).toBeVisible({ timeout: 90000 });
    }

    async continueAfterStart() {
        const firstPromptDeadline = Date.now() + 90000;
        while (Date.now() < firstPromptDeadline) {
            if (await isVisible(this.domainFirstQuestion, 500) || await isVisible(this.mediaNamePrompt, 500)) {
                break;
            }
        }

        if (await isVisible(this.domainFirstQuestion, 2000)) {
            const skipDomainButton = this.page.getByRole('button', {
                name: /skip|no|without domain|use general knowledge/i
            }).first();

            if (await skipDomainButton.isVisible({ timeout: 3000 }).catch(() => false)) {
                await skipDomainButton.click();
            } else {
                await this.chatInput.fill('No, proceed without creating a domain');
                await this.chatInput.press('Enter');
            }
        }

        await expect(this.mediaNamePrompt).toBeVisible({ timeout: 90000 });
    }

    async provideMediaName() {

        const mediaName = `Automation Media creation ${new Date().toISOString()}`;
        await this.chatInput.fill(mediaName);
        await this.chatInput.press('Enter');

        await this.page.getByText(
            'Great, now please describe your media'
        ).waitFor({ timeout: 30000 });
    }

    async provideDescription() {

        await this.chatInput.fill('desc');
        await this.chatInput.press('Enter');

        await this.page.getByRole('button', { name: 'Select file to upload' })
            .waitFor({ timeout: 30000 });
    }

    async uploadMedia(filePath: string) {

        const uploadButton = this.page.getByRole('button', {
            name: 'Select file to upload'
        });
        const fileInput = this.page.locator('input[type="file"]').first();

        await expect(uploadButton).toBeVisible({ timeout: 30000 });
        await expect(fileInput).toBeAttached({ timeout: 30000 });
        await fileInput.setInputFiles(filePath);

        await this.page.getByRole('button', { name: /^Confirm$/i }).click();

        await expect(this.contentUrlPrompt).toBeVisible({ timeout: 60000 });
    }

    async provideContentUrl(url: string) {

        await expect(this.contentUrlPrompt).toBeVisible({ timeout: 60000 });
        await expect(this.chatInput).toBeVisible({ timeout: 30000 });
        await expect(this.chatInput).toBeEditable({ timeout: 30000 });

        await this.chatInput.fill(url);
        await this.chatInput.press('Enter');

        await expect(this.sourceUrlInput).toBeVisible({ timeout: 60000 });
    }

    async provideSource(url: string) {

        await expect(this.sourceUrlInput).toBeVisible({ timeout: 60000 });
        await this.sourceUrlInput.fill(url);

        await this.dialogConfirmButton.click();

        await this.page.getByRole('button', { name: /Create Media/i })
            .waitFor({ timeout: 30000 });
    }

    async publishMedia() {

        await this.page.getByRole('button', { name: /Create Media/i }).click();

        await this.page.getByRole('button', { name: 'Maximize widget' }).click();

        await this.page.getByRole('button', { name: 'Publish' }).click();

        const priceInput = this.page.locator(
            '#media_creation_price_per_single_percent input[type="text"]'
        );

        await priceInput.fill('1');

        await this.page.locator('#btn_confirm_publish_media').click();
    }
}
