package com.zjty.automatedtesting.service;

import com.google.common.collect.Lists;
import com.zjty.automatedtesting.common.action.Assertion;
import com.zjty.automatedtesting.common.action.Browser;
import com.zjty.automatedtesting.pojo.report.Measure;
import com.zjty.automatedtesting.pojo.report.ReportVo;
import com.zjty.automatedtesting.pojo.test.Step;
import com.zjty.automatedtesting.pojo.test.CaseVo;
import com.zjty.automatedtesting.util.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.zjty.automatedtesting.common.action.Action.*;
import static com.zjty.automatedtesting.common.action.ByType.*;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;

/**
 * @author C
 */
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
@Slf4j
@Service
public class SeleniumServiceImpl implements SeleniumService {


    @Autowired
    ReportService reportService;


    @Override
    public ReportVo execute(CaseVo testCase) {
        WebDriver driver = initDriver(testCase.getBrowser());
        driver.get(testCase.getUrl());
        return executeSteps(testCase.getUrl(), driver, testCase);
    }

    /**
     * 初始化driver
     *
     * @return driver
     */
    private WebDriver initDriver(String browser) {
        if (Objects.equals(browser, Browser.FIREFOX)) {
            System.setProperty("webdriver.firefox.driver", CommonUtils.FIRE_FOX_EXE);
            return new FirefoxDriver();
        } else if (Objects.equals(browser, Browser.CHROME)) {
            System.setProperty("webdriver.chrome.driver", CommonUtils.CHROME_EXE);
            return new ChromeDriver();
        } else if (Objects.equals(browser, Browser.IE)) {
            System.setProperty("webdriver.ie.driver", CommonUtils.IE_EXE);
            return new ChromeDriver();
        } else {
            throw new RuntimeException("该浏览器不存在：" + browser);
        }
    }

    private ReportVo executeSteps(String url, WebDriver driver, CaseVo testCase) {
        List<Measure> measures = Lists.newArrayList();
        List<Step> steps = testCase.getSteps().stream().sorted(Comparator.comparingInt(Step::getOrder)).collect(Collectors.toList());
        for (Step step : steps) {
            boolean success = false;
            String practice = null;
            String message;
            WebElement webElement = null;
            log.info("执行步骤:{}", step.getTitle());
            try {
                if (Objects.equals(step.getAction(), HOME)) {
                    driver.get(url);
                } else {
                    webElement = getWebElement(step.getType(), step.getKey(), driver);
                    if (Objects.equals(step.getAction(), INPUT)) {
                        String value = isNull(step.getValue()) ? "" : step.getValue();
                        webElement.sendKeys(value);
                    } else if (Objects.equals(step.getAction(), CLICK)) {
                        webElement.click();
                    } else if (Objects.equals(step.getAction(), SWITCH)) {
                        driver.switchTo().frame(webElement);
                    } else {
                        throw new RuntimeException("不匹配的操作类型：" + step.getAction());
                    }

                }
                if (Objects.equals(step.getAssertion(), Assertion.VALUE)) {
                    if (nonNull(webElement)) {
                        practice = webElement.getAttribute("value");
                    }
                } else if (Objects.equals(step.getAssertion(), Assertion.TITLE)) {
                    practice = driver.getTitle();
                } else {
                    throw new RuntimeException("不匹配的判断类型：" + step.getAssertion());
                }
                if (Objects.equals(practice, step.getExpected())) {
                    success = true;
                    message = "成功";
                } else {
                    message = String.format("失败 实际与预期不符  预期:[%s]  实际:[%s] ", step.getExpected(), practice);
                }
            } catch (Exception e) {
                e.printStackTrace();
                success = false;
                message = String.format("出现错误:[%s]", e.getMessage());
                log.error("出现错误:", e);
            }
            measures.add(new Measure(
                    step.getOrder(),
                    step.getTitle(),
                    success,
                    step.getAssertion(),
                    step.getExpected(),
                    practice,
                    message
            ));
        }
        ReportVo reportVo = new ReportVo(
                null,
                testCase.getTitle(),
                testCase.getBrowser(),
                testCase.getUrl(),
                measures
        );
        Integer id = reportService.save(reportVo);
        reportVo.setId(id);
        return reportVo;
    }

    @SuppressWarnings("DuplicatedCode")
    private WebElement getWebElement(String getMethod, String key, WebDriver driver) {
        WebElement webElement = null;

        if (Objects.equals(getMethod, XPATH)) {
            webElement = driver.findElement(By.xpath(key));
        } else if (Objects.equals(getMethod, CSS)) {
            webElement = driver.findElement(By.cssSelector(key));
        } else if (Objects.equals(getMethod, ID)) {
            webElement = driver.findElement(By.id(key));
        } else if (Objects.equals(getMethod, NAME)) {
            webElement = driver.findElement(By.name(key));
        }

        if (Objects.nonNull(webElement)) {
            return webElement;
        } else {
            throw new RuntimeException("未找到元素  定位方式：" + getMethod + "   关键值: " + key);
        }

    }

}
