package com.clanstop.healing.driver;

import com.clanstop.healing.config.FrameworkConfig;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.edge.EdgeOptions;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.safari.SafariOptions;

import java.util.HashMap;
import java.util.Map;

/**
 * Cross-browser cloud grid support (L3git). Turns grid/healing config into the RemoteWebDriver
 * capabilities for a plain Selenium Grid / Selenoid or a cloud vendor (BrowserStack, Sauce Labs,
 * LambdaTest). Zero extra dependencies - RemoteWebDriver and every browser's Options class ship
 * inside selenium-java.
 *
 * <p>When a hub URL is configured ({@code grid.url} while {@code grid.enabled=true}, otherwise the
 * legacy {@code healing.remote.url}) both driver builders route through here instead of launching a
 * local browser. The grid browser is chosen independently of the local one ({@code grid.browser}),
 * so the same suite can fan out across Chrome, Firefox, Edge, and Safari on the grid - the same
 * generated code, a different capability set per run.
 */
public final class GridCapabilities {

    private GridCapabilities() { }

    /**
     * The hub to dial, or {@code null} to run locally. {@code grid.url} (when {@code grid.enabled})
     * wins; otherwise it falls back to the legacy {@code healing.remote.url} so existing setups keep
     * working unchanged.
     */
    public static String hubUrl(FrameworkConfig cfg) {
        if (cfg.gridEnabled() && cfg.gridUrl() != null) {
            return cfg.gridUrl();
        }
        return cfg.remoteUrl();
    }

    /** Build the capabilities for the hub: the chosen browser, version/platform, and a vendor block. */
    public static MutableCapabilities build(FrameworkConfig cfg) {
        String browser = cfg.gridBrowser() != null ? cfg.gridBrowser() : cfg.browser();
        boolean headless = cfg.headless();
        MutableCapabilities options;
        switch (browser.toLowerCase()) {
            case "firefox":
                FirefoxOptions ff = new FirefoxOptions();
                if (headless) { ff.addArguments("-headless"); }
                options = ff;
                break;
            case "edge":
                EdgeOptions ed = new EdgeOptions();
                if (headless) { ed.addArguments("--headless=new"); }
                ed.addArguments("--no-sandbox", "--disable-dev-shm-usage", "--window-size=1280,900");
                options = ed;
                break;
            case "safari":
                options = new SafariOptions();   // Safari has no headless mode
                break;
            default:
                ChromeOptions ch = new ChromeOptions();
                if (headless) { ch.addArguments("--headless=new"); }
                ch.addArguments("--no-sandbox", "--disable-dev-shm-usage", "--window-size=1280,900");
                options = ch;
        }
        if (cfg.gridBrowserVersion() != null) { options.setCapability("browserVersion", cfg.gridBrowserVersion()); }
        if (cfg.gridPlatform() != null)       { options.setCapability("platformName", cfg.gridPlatform()); }

        applyVendor(options, cfg);
        return options;
    }

    /** Add the vendor-specific options block + credentials so the cloud accepts and labels the run. */
    private static void applyVendor(MutableCapabilities options, FrameworkConfig cfg) {
        String vendor = cfg.gridVendor();
        if (vendor == null || vendor.isBlank() || vendor.equals("generic")) {
            return;   // plain Selenium Grid / Selenoid: no vendor block, no auth
        }
        String user = cfg.gridUser();
        String key = cfg.gridKey();
        String build = cfg.gridBuild() != null ? cfg.gridBuild() : "L3git";
        Map<String, Object> v = new HashMap<>();
        switch (vendor) {
            case "browserstack":
                if (user != null) { v.put("userName", user); }
                if (key != null)  { v.put("accessKey", key); }
                v.put("buildName", build);
                v.put("sessionName", "L3git suite");
                options.setCapability("bstack:options", v);
                break;
            case "saucelabs":
            case "sauce":
                if (user != null) { v.put("username", user); }
                if (key != null)  { v.put("accessKey", key); }
                v.put("build", build);
                v.put("name", "L3git suite");
                options.setCapability("sauce:options", v);
                break;
            case "lambdatest":
                if (user != null) { v.put("user", user); }
                if (key != null)  { v.put("accessKey", key); }
                v.put("build", build);
                v.put("name", "L3git suite");
                options.setCapability("LT:Options", v);
                break;
            default:
                // Unknown vendor name -> behave like a generic Grid (no vendor block).
                break;
        }
    }
}
