package net.northking.cctp.element.mobile.thread;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.ios.IOSDriver;
import net.northking.cctp.element.core.DeviceDriver;
import net.northking.cctp.element.core.IExecuteContext;
import net.northking.cctp.element.core.IStepTarget;
import net.northking.cctp.element.core.exception.ExecuteException;
import net.northking.cctp.element.core.exception.ParamMistakeException;
import net.northking.cctp.element.mobile.constants.ConfigPath;
import net.northking.cctp.element.mobile.constants.UsingType;
import net.northking.cctp.element.mobile.entity.StepTarget;
import net.northking.cctp.element.mobile.utils.CommonUtils;
import net.northking.cctp.element.mobile.utils.HttpUtils;
import net.northking.cctp.element.mobile.utils.phoneUtils.ElementUtil;
import org.openqa.selenium.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

public class GetTableColValueThread implements Callable<String> {

    private Logger logger = LoggerFactory.getLogger(GetTableColValueThread.class);

    private IExecuteContext context;
    private DeviceDriver deviceDriver;
    private List<IStepTarget> targets;
    private String referenceStr;
    private Integer waitTimeout;
    private String waitStatusStr;
    private Integer index;
    private Float preExecuteWait;
    private Float sufExecuteWait;

    public GetTableColValueThread(IExecuteContext context, DeviceDriver deviceDriver, List<IStepTarget> targets, String referenceStr, Integer waitTimeout, String waitStatusStr, Float preExecuteWait, Float sufExecuteWait, Integer index) {
        this.context = context;
        this.deviceDriver = deviceDriver;
        this.targets = targets;
        this.referenceStr = referenceStr;
        this.waitTimeout = waitTimeout;
        this.waitStatusStr = waitStatusStr;
        this.index = index;
        this.preExecuteWait = preExecuteWait;
        this.sufExecuteWait = sufExecuteWait;
    }

    @Override
    public String call() throws Exception {
        CommonUtils.handlePreExecuteWait(preExecuteWait);
        boolean waitStatus = "1".equals(waitStatusStr);
        if (null == waitTimeout || waitTimeout <= 0) {
            waitTimeout = 30;
        }
        List<StepTarget> references = JSONObject.parseArray(referenceStr, StepTarget.class);
        List<IStepTarget> iStepTargets = new ArrayList<>();
        for (StepTarget reference : references) {
            iStepTargets.add(reference);
        }
        List<String> resultList = new ArrayList<>();
        String result = "";
        AppiumDriver<WebElement> driver = (AppiumDriver<WebElement>) deviceDriver;

        Rectangle rectangleTitle = xpathFind(driver, targets);
        Rectangle rectangleTable = xpathFind(driver, iStepTargets);

        if (rectangleTitle != null && rectangleTable != null) {
            resultList = getElementValueByOcr(context, driver, rectangleTitle, rectangleTable);
        }
        CommonUtils.handleSufExecuteWait(sufExecuteWait);
        return JSON.toJSONString(resultList);
    }

    /**
     * xpath找元素
     *
     * @param driver
     * @param targets
     */
    private Rectangle xpathFind(AppiumDriver<WebElement> driver, List<IStepTarget> targets) {
        WebElement webElement = null;
        Rectangle rect = null;
        for (IStepTarget target : targets) {
            JSONObject object = JSON.parseObject(target.getValue(), JSONObject.class);
            String xpath = object.getString(UsingType.Key.SELECTOR_KEY);
            logger.info("拿到的xpath:{}", xpath);
            try {
                driver.manage().timeouts().implicitlyWait(waitTimeout, TimeUnit.SECONDS);
            } catch (NoSuchSessionException e) {
                throw e;
            }
            List<WebElement> elements = null;
            try {
                elements = driver.findElements(By.xpath(xpath));
            } catch (WebDriverException e) {
                logger.error("driver查找控件异常：", e);
                throw e;
            }
            logger.info("找到元素{}个", elements.size());
            if (!CollectionUtils.isEmpty(elements)) {   //xpath找到了
                webElement = elements.get(0);
                try {
                    rect = webElement.getRect();
                } catch (StaleElementReferenceException e) {
                    logger.warn("页面发生了变化，重新查找元素", e);
                    try {
                        Thread.sleep(3000L);
                    } catch (InterruptedException ex) {
                        logger.error("再查找元素等待时被打断", ex);
                    }
                    logger.info("再次查找当前页面的元素");
                    // 可能由于页面元素发生变化导致dom结构发生变化
                    elements = driver.findElements(By.xpath(xpath));
                    if (null != elements) {
                        rect = elements.get(0).getRect();
                    }
                }
            }
            if (rect != null) {
                return rect;
            }
            break;
        }
        return rect;
    }

    public List<String> getElementValueByOcr(IExecuteContext context, AppiumDriver<WebElement> driver, Rectangle rectTitle, Rectangle rectTable) {
        String imgBase64 = null;
        try {
            imgBase64 = ocrFindCodeArea(rectTitle, rectTable, driver, context);
        } catch (ExecuteException | ParamMistakeException | WebDriverException e) {
            throw e;
        } catch (Exception e) {
            logger.error("查找区域截图失败", e);
            throw new ExecuteException("查找区域截图失败");
        }
        if (null == imgBase64) {
            throw new ExecuteException("未截取到区域");
        }
        String ocrAddress = context.getProperty(ConfigPath.OCR_GET_TABLE_COL_VALUE);
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            Map<String, Object> ocrParamMap = new HashMap<>();
            ocrParamMap.put("img_base64", imgBase64);
            ocrParamMap.put("line", index);
            HttpEntity<Map> ocrEntity = new HttpEntity<>(ocrParamMap, headers);
            List ocrResultList = new ArrayList();
            try {
                logger.info("传参：{}", JSON.toJSONString(ocrParamMap));
                ocrResultList = HttpUtils.doPost(ocrAddress, ocrEntity, List.class);
                logger.info("得到的ocr结果：{}", ocrResultList);
            } catch (Exception e) {
                logger.error("ocr失败", e);
            }
            if (!CollectionUtils.isEmpty(ocrResultList) && ocrResultList.size() > 0) {
                // 不要标题
                return ocrResultList.subList(1, ocrResultList.size());
            }
            return ocrResultList;
        } catch (Exception e) {
            logger.error("请求ocr接口失败，接口地址：{}", ocrAddress, e);
            throw new ExecuteException("请求ocr识别接口失败，请查看ocr识别服务是否开启！");
        }
    }

    public String ocrFindCodeArea(Rectangle rectTitle, Rectangle rectTable, AppiumDriver<WebElement> driver, IExecuteContext context) {
        String result = null;
        // 表格标题区域
        logger.info("rectTitle:{}", JSON.toJSONString(rectTitle));
        int xTitle = rectTitle.getX();
        int yTitle = rectTitle.getY();
        int widthTitle = rectTitle.getWidth();

        // 表格区域
        logger.info("rectTable:{}", JSON.toJSONString(rectTable));
        int heightTable = rectTable.getHeight();

        // 真实截图位置 x=表格标题x，y=表格标题y+表格标题高，宽=表格高-标题高，高=表格宽
        int x = xTitle;
        int y = yTitle;
        int width = heightTable;
        int height =  widthTitle;

        Map<String, Object> deviceInfo = context.getDeviceInfo();
        String resolution = (String) deviceInfo.get("resolution");
        String[] split = resolution.split("\\*");
        int screenLength = Integer.parseInt(split[0]);
        int screenWidth = Integer.parseInt(split[1]);
        logger.info("通过xpth找到元素的x：{}，y：{}， width：{}， height：{}，screenLength：{}，screenWidth：{}", x, y, width, height, screenLength, screenWidth);
        Map<String, Object> paramMap = new HashMap<>();
        if (driver instanceof IOSDriver) {
            paramMap.put("platform", "1");
        } else {
            paramMap.put("platform", "0");
        }
        paramMap.put("deviceId", driver.getCapabilities().getCapability("deviceName"));
        paramMap.put("length", height);
        paramMap.put("width", width);
        paramMap.put("resolution", resolution);
        paramMap.put("x", x);
        paramMap.put("y", y);
        paramMap.put("screenLength", screenLength);
        paramMap.put("screenWidth", screenWidth);
        logger.info("参数：{}", JSON.toJSONString(paramMap));
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(paramMap);
        String host = driver.getRemoteAddress().getHost();  //上位机地址
        String port = (String) deviceInfo.get("port");   //上位机端口
        String mobileShotAddress = context.getProperty(ConfigPath.MOBILE_SHOT_ADDRESS_KEY);
        String shotScreenAddress = String.format(ConfigPath.HTTP_FORMAT, host, port, mobileShotAddress);
        try {
            result = HttpUtils.doPost(shotScreenAddress, entity, String.class);
        } catch (Exception e) {
            logger.error("截图失败", e);
        }
        return result;
    }
}
