package ru.otus.mobile.tests;

import com.codeborne.selenide.Configuration;
import com.codeborne.selenide.WebDriverRunner;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import ru.otus.mobile.db.DbClient;
import ru.otus.mobile.db.DbConfig;
import ru.otus.mobile.config.MobileConfig;
import ru.otus.mobile.config.AuthContext;
import ru.otus.mobile.config.MobileContext;
import ru.otus.mobile.driver.MobileDriverFactory;
import ru.otus.mobile.screens.LoginScreen;
import ru.otus.mobile.ui.MobileUi;
import ru.otus.mobile.util.TestAccount;

public abstract class BaseMobileTest {
    protected MobileConfig config;

    @BeforeEach
    void setUp() {
        config = MobileConfig.load();
        MobileContext.init(config);
        Configuration.timeout = 0;
        Configuration.browserSize = null;
        ensureCredentials();
        setActiveCredentials();
        resetData();
        WebDriverRunner.setWebDriver(MobileDriverFactory.create(config));
        loginIfNeeded();
    }

    @AfterEach
    void tearDown() {
        WebDriverRunner.closeWebDriver();
    }

    protected void loginIfNeeded() {
        LoginScreen loginScreen = new LoginScreen();
        if (loginScreen.isVisible()) {
            loginScreen.loginOrRegister(accountUsername(), accountPassword(), allowRegister());
            return;
        }
        if (MobileUi.existsById("wishlists_content")
                || MobileUi.existsById("users_content")) {
            return;
        }
        throw new IllegalStateException("App did not reach login or main screen.");
    }

    protected abstract TestAccount account();

    private void resetData() {
        DbConfig dbConfig = DbConfig.load();
        String sql = account().resetSql() != null ? account().resetSql() : dbConfig.resetSql();
        DbClient client = new DbClient(dbConfig);
        if (account() == TestAccount.RESERVATION) {
            client.resetReservationData(accountUsername(), reservationOwnerUsername(), sql);
        } else {
            client.resetUserData(accountUsername(), sql);
        }
    }

    private String accountUsername() {
        String accountKey = account().name().toLowerCase();
        String prop = System.getProperty("login.username." + accountKey);
        if (prop != null && !prop.isBlank()) {
            return prop;
        }
        String env = System.getenv("LOGIN_USERNAME_" + accountKey.toUpperCase());
        if (env != null && !env.isBlank()) {
            return env;
        }
        return account().username();
    }

    private String accountPassword() {
        String accountKey = account().name().toLowerCase();
        String prop = System.getProperty("login.password." + accountKey);
        if (prop != null && !prop.isBlank()) {
            return prop;
        }
        String env = System.getenv("LOGIN_PASSWORD_" + accountKey.toUpperCase());
        if (env != null && !env.isBlank()) {
            return env;
        }
        String common = System.getProperty("login.password");
        if (common != null && !common.isBlank()) {
            return common;
        }
        return "Admin123";
    }

    private boolean allowRegister() {
        return System.getProperty("login.auto." + account().name().toLowerCase()) != null;
    }

    private void ensureCredentials() {
        String accountKey = account().name().toLowerCase();
        String prop = System.getProperty("login.username." + accountKey);
        String env = System.getenv("LOGIN_USERNAME_" + accountKey.toUpperCase());
        if ((prop == null || prop.isBlank()) && (env == null || env.isBlank())) {
            String generated = "auto_" + accountKey + "_" + System.currentTimeMillis();
            System.setProperty("login.username." + accountKey, generated);
            System.setProperty("login.password." + accountKey, "Admin123");
            System.setProperty("login.auto." + accountKey, "true");
        }
        if (account() == TestAccount.RESERVATION && System.getProperty("reservation.owner") == null) {
            System.setProperty("reservation.owner", "user4us");
        }
    }

    private void setActiveCredentials() {
        System.setProperty("login.account.active", account().name().toLowerCase());
        System.setProperty("login.username.active", accountUsername());
        System.setProperty("login.password.active", accountPassword());
        System.setProperty("login.auto.active", Boolean.toString(allowRegister()));
        AuthContext.init(accountUsername(), accountPassword(), allowRegister());
    }

    private String reservationOwnerUsername() {
        String prop = System.getProperty("reservation.owner");
        if (prop != null && !prop.isBlank()) {
            return prop;
        }
        String env = System.getenv("RESERVATION_OWNER");
        if (env != null && !env.isBlank()) {
            return env;
        }
        return "user4us";
    }
}
