package de.avatic.lcc.e2e.pages;

import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.options.LoadState;
import com.microsoft.playwright.options.WaitForSelectorState;

import java.util.logging.Logger;

/**
 * Base class for all Playwright Page Objects.
 * Provides common interaction methods for UI elements.
 */
public abstract class BasePage {

    private static final Logger logger = Logger.getLogger(BasePage.class.getName());

    protected final Page page;

    protected BasePage(Page page) {
        this.page = page;
    }

    /**
     * Waits until the SPA navigates to a route containing the expected part.
     */
    protected void waitForSpaNavigation(String expectedRoutePart) {
        page.waitForURL("**" + expectedRoutePart + "**");
        page.waitForLoadState(LoadState.NETWORKIDLE);
    }

    /**
     * Waits for an element to be visible.
     */
    protected Locator waitForElement(String selector) {
        Locator locator = page.locator(selector);
        locator.waitFor(new Locator.WaitForOptions().setState(WaitForSelectorState.VISIBLE));
        return locator;
    }

    /**
     * Waits for an element to be visible with a custom timeout.
     */
    protected Locator waitForElement(String selector, double timeoutMs) {
        Locator locator = page.locator(selector);
        locator.waitFor(new Locator.WaitForOptions()
            .setState(WaitForSelectorState.VISIBLE)
            .setTimeout(timeoutMs));
        return locator;
    }

    /**
     * Clears and fills an input field.
     */
    protected void fillInput(Locator locator, String text) {
        locator.clear();
        locator.fill(text);
        logger.info(() -> "Filled input with: " + text);
    }

    /**
     * Clears and fills an input field by selector.
     */
    protected void fillInput(String selector, String text) {
        Locator locator = waitForElement(selector);
        fillInput(locator, text);
    }

    /**
     * Fills an input field if it exists, returns false if element not found.
     */
    protected boolean fillInputIfExists(String selector, String text, double timeoutMs) {
        try {
            Locator locator = page.locator(selector);
            locator.waitFor(new Locator.WaitForOptions()
                .setState(WaitForSelectorState.VISIBLE)
                .setTimeout(timeoutMs));
            fillInput(locator, text);
            return true;
        } catch (Exception e) {
            logger.warning(() -> "Element not found, skipping: " + selector);
            return false;
        }
    }

    /**
     * Clicks a button by selector.
     */
    protected void clickButton(String selector) {
        Locator button = waitForElement(selector);
        button.click();
        logger.info(() -> "Clicked button: " + selector);
    }

    /**
     * Clicks a button by its visible text.
     */
    protected void clickButtonByText(String buttonText) {
        Locator button = page.getByText(buttonText);
        button.waitFor(new Locator.WaitForOptions().setState(WaitForSelectorState.VISIBLE));
        button.click();
        logger.info(() -> "Clicked button with text: " + buttonText);
    }

    /**
     * Clicks a button by its visible text with custom timeout.
     */
    protected void clickButtonByText(String buttonText, double timeoutMs) {
        Locator button = page.getByText(buttonText);
        button.waitFor(new Locator.WaitForOptions()
            .setState(WaitForSelectorState.VISIBLE)
            .setTimeout(timeoutMs));
        button.click();
        logger.info(() -> "Clicked button with text: " + buttonText);
    }

    /**
     * Sets a checkbox to the desired state.
     */
    protected void setCheckbox(String labelSelector, boolean checked) {
        Locator label = page.locator(labelSelector);
        label.waitFor(new Locator.WaitForOptions().setState(WaitForSelectorState.VISIBLE));

        Locator checkbox = label.locator("input[type='checkbox']");
        boolean isChecked = checkbox.isChecked();

        if (isChecked != checked) {
            label.click();
            page.waitForTimeout(300);
            logger.info(() -> "Toggled checkbox to: " + checked);
        }
    }

    /**
     * Selects an option from a dropdown menu.
     */
    protected void selectDropdownOption(String triggerSelector, String optionText) {
        Locator dropdownTrigger = waitForElement(triggerSelector);

        // Check if already has the correct value
        try {
            String currentValue = dropdownTrigger.locator("span.dropdown-trigger-text").textContent();
            if (optionText.equals(currentValue)) {
                logger.info(() -> "Dropdown already has value: " + optionText);
                return;
            }
        } catch (Exception ignored) {
            // Continue to open dropdown
        }

        dropdownTrigger.click();
        logger.info("Opened dropdown");

        Locator menu = page.locator("ul.dropdown-menu");
        menu.waitFor(new Locator.WaitForOptions().setState(WaitForSelectorState.VISIBLE));

        String optionXPath = String.format(
            "//li[contains(@class, 'dropdown-option')][normalize-space(text())='%s']",
            optionText
        );
        Locator option = page.locator(optionXPath);
        option.click();

        logger.info(() -> "Selected dropdown option: " + optionText);
        page.waitForTimeout(200);
    }

    /**
     * Searches in an autosuggest input and selects the first suggestion.
     */
    protected void searchAndSelectAutosuggest(String inputSelector, String searchText) {
        searchAndSelectAutosuggest(inputSelector, searchText, ".suggestion-item");
    }

    /**
     * Searches in an autosuggest input and selects from suggestions.
     */
    protected void searchAndSelectAutosuggest(String inputSelector, String searchText, String suggestionSelector) {
        Locator input = waitForElement(inputSelector);
        input.clear();
        input.fill(searchText);

        page.waitForTimeout(1000);

        Locator suggestion = page.locator(suggestionSelector).first();
        suggestion.waitFor(new Locator.WaitForOptions().setState(WaitForSelectorState.VISIBLE));
        suggestion.click();

        page.waitForTimeout(500);
        logger.info(() -> "Selected autosuggest for: " + searchText);
    }

    /**
     * Waits for a modal to close.
     */
    protected void waitForModalToClose() {
        page.locator("div.modal-container").waitFor(
            new Locator.WaitForOptions().setState(WaitForSelectorState.HIDDEN)
        );
    }

    /**
     * Takes a screenshot for debugging purposes.
     */
    protected void takeScreenshot(String name) {
        page.screenshot(new Page.ScreenshotOptions()
            .setPath(java.nio.file.Paths.get("target/screenshots/" + name + ".png")));
    }
}
