<?php

namespace Ecomnova;

use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\RemoteWebElement;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverExpectedCondition;
use Facebook\WebDriver\WebDriverWait;



abstract class EcomnovaPage extends EcomnovaAbstract
{
    const DRIVER_CHROME = 'chrome';
    protected $testUrl;

    /**
     * @var RemoteWebDriver
     */
    protected $driver;

    public function __construct($testUrl = 'http://localhost:4444')
    {
        $this->testUrl = $testUrl;
    }

    public function init($browser = self::DRIVER_CHROME)
    {
        try {
            $this->getDriver($browser);
        } catch (\Exception $e) {
            throw new \Exception("Could not create driver, {$e->getMessage()}");
        }

    }
    public function getDriver($browser = self::DRIVER_CHROME): RemoteWebDriver
    {
        switch ($browser) {
            case self::DRIVER_CHROME:
                if ($this->driver === null) {
                    $this->driver = $this->getChromeDriver();
                }
                return $this->driver;
            default:
                throw new \Exception('Invalid browser type');
        }
    }

    private function getChromeDriver(): RemoteWebDriver
    {
        $options = new ChromeOptions();
        $options->addArguments([
            '--headless', // Optional: Use headless mode
            '--no-sandbox',
            '--disable-dev-shm-usage',
            '--user-data-dir=' . sys_get_temp_dir() . '/chrome-user-data-' . uniqid()
        ]);

        $capabilities = DesiredCapabilities::chrome();
        $capabilities->setCapability(ChromeOptions::CAPABILITY, $options);

        return RemoteWebDriver::create($this->testUrl, $capabilities);
    }

    public function setTestUrl(string $testUrl): EcomnovaPage
    {
        $this->testUrl = $testUrl;
        return $this;
    }

    public function openProductPage($url)
    {
        $this->driver->get($url);
        $this->waitForPageLoad();
        return $this->driver;
    }

    /**
     * Wait for the page to load completely
     * This method waits for the 'body' element to be present.
     * You can customize it further to wait for specific elements.
     *
     * @param int $timeout Timeout in seconds (default is 10 seconds)
     */
    protected function waitForPageLoad($timeout = 10)
    {
        $wait = new WebDriverWait($this->driver, $timeout);
        $wait->until(
            WebDriverExpectedCondition::presenceOfElementLocated(WebDriverBy::tagName('body'))
        );
    }

    /**
     * Wait for an element to be present in the DOM
     * @param string $cssSelector The CSS selector of the element
     * @param int $timeout Timeout in seconds
     * @return RemoteWebElement
     * @throws \Exception If the element is not found within the timeout
     */
    protected function waitForElement($cssSelector, $timeout = 10): RemoteWebElement
    {
        $wait = new WebDriverWait($this->driver, $timeout);
        try {
            return $wait->until(
                WebDriverExpectedCondition::presenceOfElementLocated(WebDriverBy::cssSelector($cssSelector))
            );
        } catch (\Exception $e) {
            throw new \Exception("Element with selector '$cssSelector' not found within $timeout seconds.");
        }
    }

    /*
    * Get selector for an element by label
    * @param string $label
    */
    protected function getLabelXpath($label): string
    {
        return "//label[ contains (text(), '$label' ) ]";
    }

    /**
     * Find the first radio button in a parent element
     * @param RemoteWebElement $element
     * @param bool $debug - if true, will var_dump the innerHTML of the parent element
     * @return RemoteWebElement
     */
    protected function getParentElement(RemoteWebElement $element, $debug = false): RemoteWebElement
    {
        $parent = $element->findElement(WebDriverBy::xpath('..'));
        if ($debug) {
            var_dump($parent->getDomProperty('innerHTML'));
        }
        return $parent;
    }

    /*
    * Find the first radio button in a parent element
    * @param RemoteWebElement $parent
    * @param bool $selected - if true, will find the selected radio button
    * @return RemoteWebElement
    */
    protected function findFirstRadioButton(RemoteWebElement $parent, $selected = false): RemoteWebElement
    {
        if ($selected) {
            return $parent->findElement(WebDriverBy::cssSelector('input[type="radio"]:checked'));
        }
        return $parent->findElement(WebDriverBy::xpath('.//input[@type="radio"]'));
    }

    /*
    * Find the first checkbox in a parent element
    * @param RemoteWebElement $parent
    * @return RemoteWebElement
    */
    protected function findFirstCheckbox(RemoteWebElement $parent): RemoteWebElement
    {
        return $parent->findElement(WebDriverBy::xpath('.//input[@type="checkbox"]'));
    }

    public function __destruct()
    {
        if ($this->driver !== null) {
            $this->driver->quit();
        }
    }

    public static function getTesterInstance(string $className, $type = EcomnovaPage::WEBSITE_AY_DESKTOP)
    {
        switch ($className) {
            case ProductPageInterface::class:
                return PageClassFactory::getProductPageInstance($type);
            case CartPageInterface::class:
                return PageClassFactory::createCartPageInstance($type);
            case CategoryPageInterface::class:
                return PageClassFactory::createCategoryPageInstance($type);
            default:
                throw new \Exception('Invalid class type');
        }
    }
}
