package ru.otus.mobile.driver;

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import ru.otus.mobile.config.MobileConfig;

import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Duration;

public final class MobileDriverFactory {
    private MobileDriverFactory() {
    }

    public static WebDriver create(MobileConfig config) {
        UiAutomator2Options options = new UiAutomator2Options()
                .setPlatformName("Android")
                .setAutomationName("UiAutomator2")
                .setDeviceName(config.deviceName())
                .setApp(config.appPath())
                .setAppPackage(config.appPackage())
                .setAppActivity(config.appActivity())
                .setAutoGrantPermissions(true)
                .setNewCommandTimeout(Duration.ofSeconds(config.newCommandTimeoutSeconds()))
                .setAppWaitActivity("*");

        if (config.platformVersion() != null && !config.platformVersion().isBlank()) {
            options.setPlatformVersion(config.platformVersion());
        }
        if (config.udid() != null && !config.udid().isBlank()) {
            options.setUdid(config.udid());
        }
        options.setNoReset(config.noReset());
        options.setCapability("appium:settingsAppWaitDuration", 60000);
        options.setCapability("appium:uiautomator2ServerInstallTimeout", 60000);
        options.setCapability("appium:uiautomator2ServerLaunchTimeout", 60000);
        options.setCapability("appium:appWaitDuration", 60000);

        try {
            URL appiumUrl = new URL(config.appiumUrl());
            assertAppiumReady(appiumUrl);
            return createWithDeviceRetry(appiumUrl, options);
        } catch (MalformedURLException e) {
            throw new IllegalStateException("Invalid Appium URL: " + config.appiumUrl(), e);
        }
    }

    private static WebDriver createWithDeviceRetry(URL appiumUrl, UiAutomator2Options options) {
        long deadline = System.currentTimeMillis() + 180_000;
        WebDriverException last = null;
        while (System.currentTimeMillis() < deadline) {
            try {
                return new AndroidDriver(appiumUrl, options);
            } catch (WebDriverException e) {
                last = e;
                String message = e.getMessage();
                if (message != null && message.contains("Could not find a connected Android device")) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException interruptedException) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                    continue;
                }
                if (message != null && message.contains("Appium Settings app is not running")) {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException interruptedException) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                    continue;
                }
                throw e;
            }
        }
        if (last != null) {
            throw last;
        }
        throw new WebDriverException("Android device was not detected within timeout.");
    }

    private static void assertAppiumReady(URL appiumUrl) {
        try {
            URL statusUrl = new URL(appiumUrl.toString() + "/status");
            HttpURLConnection connection = (HttpURLConnection) statusUrl.openConnection();
            connection.setConnectTimeout(3000);
            connection.setReadTimeout(3000);
            connection.setRequestMethod("GET");
            int code = connection.getResponseCode();
            if (code >= 400) {
                throw new IllegalStateException("Appium status returned HTTP " + code);
            }
        } catch (Exception e) {
            throw new WebDriverException("Appium is not reachable at " + appiumUrl + ". " +
                    "Make sure docker compose is up and Appium is healthy.", e);
        }
    }
}
