// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.

import * as assert from "assert";
import { Application } from "../../automation";
import { AppiumClient, AppiumHelper } from "./helpers/appiumHelper";
import { SmokeTestLogger } from "./helpers/smokeTestLogger";
import { SmokeTestsConstants } from "./helpers/smokeTestsConstants";
import { TestRunArguments } from "./helpers/testConfigProcessor";
import { sleep } from "./helpers/utilities";
import { androidEmulatorManager, vscodeManager } from "./main";

const HERMES_APP_PACKAGE_NAME = `com.${SmokeTestsConstants.HermesAppName.toLocaleLowerCase()}`;
const HERMES_APP_ACTIVITY_NAME = `com.${SmokeTestsConstants.HermesAppName.toLocaleLowerCase()}.MainActivity`;
const RNHermesDebugConfigName = "Debug Android (Hermes) - Experimental";
const RNHermesAttachConfigName = "Attach to Hermes application - Experimental";

const RNHermesSetBreakpointOnLine = 11;
// Time for Android Debug Test before it reaches timeout
const debugAndroidTestTime = SmokeTestsConstants.hermesTestTimeout;

export function startDirectDebugTests(workspace: string, testParameters: TestRunArguments): void {

    describe("Direct debugging", () => {
        let app: Application | null;
        let client: AppiumClient | null;

        async function disposeAll() {
            SmokeTestLogger.info("Dispose all ...");
            if (app) {
                SmokeTestLogger.info("Stopping React Native packager ...");
                await stopPackager();
                await app.stop();
                app = null;
            }
            if (client) {
                await client.closeApp();
                await client.deleteSession();
                client = null;
            }
        }

        async function stopPackager() {
            if (app) {
                await app.workbench.quickaccess.runCommand(SmokeTestsConstants.stopPackagerCommand);
                await sleep(3000);
            }
        }

        afterEach(disposeAll);

        if (testParameters.RunAndroidTests) {
            it("Hermes RN app Debug test", async function () {
                try {
                    this.timeout(debugAndroidTestTime);
                    app = await vscodeManager.runVSCode(workspace, "Hermes RN app Debug test");
                    await app.workbench.quickaccess.openFile("AppTestButton.js");
                    await app.workbench.editors.scrollTop();
                    SmokeTestLogger.info("Android Debug Hermes test: AppTestButton.js file is opened");
                    await app.workbench.debug.setBreakpointOnLine(RNHermesSetBreakpointOnLine);
                    SmokeTestLogger.info(`Android Debug Hermes test: Breakpoint is set on line ${RNHermesSetBreakpointOnLine}`);
                    SmokeTestLogger.info(`Android Debug Hermes test: Chosen debug configuration: ${RNHermesDebugConfigName}`);
                    SmokeTestLogger.info("Android Debug Hermes test: Starting debugging");
                    await app.workbench.quickaccess.runDebugScenario(RNHermesDebugConfigName);
                    const opts = AppiumHelper.prepareAttachOptsForAndroidActivity(HERMES_APP_PACKAGE_NAME, HERMES_APP_ACTIVITY_NAME, androidEmulatorManager.getEmulatorId());
                    await androidEmulatorManager.waitUntilAppIsInstalled(HERMES_APP_PACKAGE_NAME);
                    client = await AppiumHelper.webdriverAttach(opts);
                    await app.workbench.debug.waitForDebuggingToStart();
                    SmokeTestLogger.info("Android Debug Hermes test: Debugging started");
                    SmokeTestLogger.info("Android Debug Hermes test: Checking for Hermes mark");
                    let isHermesWorking = await AppiumHelper.isHermesWorking(client);
                    assert.strictEqual(isHermesWorking, true);
                    SmokeTestLogger.info("Android Debug Hermes test: Reattaching to Hermes app");
                    await app.workbench.debug.disconnectFromDebugger();
                    await app.workbench.quickaccess.runDebugScenario(RNHermesAttachConfigName);
                    SmokeTestLogger.info("Android Debug Hermes test: Reattached successfully");
                    await sleep(7000);
                    SmokeTestLogger.info("Android Debug Hermes test: Click Test Button");
                    await AppiumHelper.clickTestButtonHermes(client);
                    await app.workbench.debug.waitForStackFrame(sf => sf.name === "AppTestButton.js" && sf.lineNumber === RNHermesSetBreakpointOnLine, `looking for AppTestButton.js and line ${RNHermesSetBreakpointOnLine}`);
                    SmokeTestLogger.info("Android Debug Hermes test: Stack frame found");
                    await app.workbench.debug.continue();
                    // await for our debug string renders in debug console
                    await sleep(SmokeTestsConstants.debugConsoleSearchTimeout);
                    let found = vscodeManager.findStringInLogs("Test output from Hermes debuggee", SmokeTestsConstants.ReactNativeLogFileName);
                    assert.notStrictEqual(found, false, "\"Test output from Hermes debuggee\" string is missing in output file");
                    if (found) {
                        SmokeTestLogger.success("Android Debug test: \"Test output from Hermes debuggee\" string is found");
                    }
                    await app.workbench.debug.disconnectFromDebugger();
                    SmokeTestLogger.info("Android Debug Hermes test: Debugging is stopped");
                } catch (e) {
                    SmokeTestLogger.error(`Android Debug Hermes test failed: ${e.toString()}`);
                    await stopPackager();
                    return this.skip();
                }
            });
        }
    });
}
