package com.tao.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.util.ReUtil;
import com.tao.mapper.AppElementMapper;
import com.tao.mapper.AppPageMapper;
import com.tao.pojo.AjaxResult;
import com.tao.pojo.AppElement;
import com.tao.pojo.AppPage;
import com.tao.service.AppElementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

@Service
public class AppElementServiceImpl implements AppElementService {

    @Autowired
    AppElementMapper appElementMapper;

    @Autowired
    AppPageMapper appPageMapper;

    /**
     * @param dirPath
     * @return AjaxResult
     * @Description 在dirPath目录里面查找page.py文件，将py文件中的元素同步到数据库中
     */
    @Override
    public AjaxResult syncElements(String dirPath) {
        appElementMapper.deleteAppElementByType(0l);
        try {
            Files.walkFileTree(Paths.get(dirPath), new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    String filePath = file.toString();
                    if (!filePath.contains("element.py") && !filePath.contains("__init__.py") && filePath.endsWith(".py")) {
                        // 创建一个页面对象，一个page.py文件对应一个对象
                        AppPage appPage = new AppPage();
                        appPage.setPageName(FileUtil.getPrefix(filePath));

                        /* 读取py文件，返回初始的元素列表 */
                        FileReader fileReader = new FileReader(filePath);
                        List<String> strings = fileReader.readLines();
                        // 用于存储初始的元素列表
                        List<StringBuilder> elements = new ArrayList<>();
                        // 此处的第一个元素是用于存放第一个元素前的内容
                        elements.add(new StringBuilder());
                        // 元素数量
                        int elementsNum = 0;
                        // 用于标识是否还在__init__方法内
                        boolean flag = false;
                        for (int i = 0; i < strings.size(); i++) {
                            String content = strings.get(i);
                            // 不处理空行且当遇到__init__时才开始元素的处理
                            if (!"".equals(content) && ReUtil.contains(Pattern.compile(" def\\s*__init"), content) || flag) {
                                flag = true;
                                // 使用行内是否有= {以及不是#号开头来判断是有存在元素
                                if (ReUtil.contains(Pattern.compile("=\\s*\\{"), content) && !content.trim().startsWith("#")) {
                                    StringBuilder stringBuilder = new StringBuilder();
                                    // 若元素第一行前有注释，则添加到初始元素内容中作为元素备注
                                    if (strings.get(i - 1).contains("#")) {
                                        stringBuilder.append(strings.get(i - 1) + "&&&&&");
                                    }
                                    elements.add(stringBuilder);
                                    elementsNum++;
                                }
                                // 将元素第一行后面的内容添加到初始元素内容中，直到下一个元素为止
                                // 此处加&&&&&是为了方便判断换行
                                elements.get(elementsNum).append(content + "&&&&&");
                                // 当下一行出现函数定义符，且不是注释行的话，则证明已跳出
                                if (i < strings.size() - 1 && ReUtil.contains(Pattern.compile(" def "), strings.get(i + 1)) && !strings.get(i + 1).startsWith("#")) {
                                    flag = false;
                                }
                            } else {
                                // 获取类名
                                if (ReUtil.contains(Pattern.compile("class.*object"), content) && !content.trim().startsWith("#")) {
                                    appPage.setPageClassName(ReUtil.get(Pattern.compile("(?<=class).*?(?=\\(\\s*object)"), content, 0).trim());
                                }
                            }
                        }
                        appPageMapper.insertAppPage(appPage);

                        /* 从初始元素列表中提取有用的信息 */
                        for (int i = 1; i < elements.size(); i++) {
                            AppElement appElement = new AppElement();
                            appElement.setElementType(0l);
                            appElement.setPageID(appPage.getPageID());
                            String elementString = elements.get(i).toString();

                            // 获取元素备注
                            String elementRemark = ReUtil.get("(?<=#).*?(?=self.)", elementString, 0);
                            if (elementRemark != null) {
                                elementRemark = elementRemark.trim();
                            }
                            appElement.setElementRemark(ReUtil.delAll(Pattern.compile("&&&&&"), elementRemark));

                            // 去除无用注释，清除换行符
                            elementString = ReUtil.delAll(Pattern.compile("#.*?&&&&&"), elementString);
                            elementString = ReUtil.delAll(Pattern.compile("&&&&&"), elementString);

                            // 获取元素名
                            String elementName = ReUtil.get(Pattern.compile("(?<=self.).*?(?==\\s*\\{)"), elementString, 0);
                            if (elementName != null) {
                                elementName = elementName.trim();
                            }
                            appElement.setElementName(ReUtil.delAll(Pattern.compile("_locator"), elementName));

                            /* 获取两端的元素定位值 */
                            String elementLocate = elementString.substring(elementString.indexOf("{") + 1, elementString.lastIndexOf("}")).trim();
                            String[] split = elementLocate.split("}\\s*,");
                            // 针对两端定制值都写了或者只写了一端但在结尾加了,号特殊处理
                            if (split.length == 2 || elementLocate.endsWith(",")) {
                                split[0] = split[0] + "}";
                            }
                            for (String s : split) {
                                try {
                                    String substring = s.substring(s.indexOf("{") + 1, s.lastIndexOf("}")).trim();
                                    if (s.contains("Android")) {
                                        appElement.setElementAndroidLocate(substring);
                                    } else {
                                        appElement.setElementIOSLocate(substring);
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                            appElementMapper.insertAppElement(appElement);
                        }
                    }
                    return super.visitFile(file, attrs);
                }
            });
            return AjaxResult.success("同步成功");
        } catch (IOException e) {
            e.printStackTrace();
            return AjaxResult.error("读取文件异常！", e);
        }

    }

    /**
     * @param id ID
     * @return com.tao.pojo.AppElement
     * @Description 根据ID查找元素
     */
    @Override
    public AppElement selectAppElementById(Long id) {
        return appElementMapper.selectAppElementById(id);
    }

    /**
     * @param elementName
     * @return com.tao.pojo.AppElement
     * @Description 根据类型来查找元素集合
     */
    @Override
    public AppElement selectAppElementByName(String elementName) {
        return appElementMapper.selectAppElementByName(elementName);
    }

    /**
     * @param pageID
     * @return java.util.List<com.tao.pojo.AppElement>
     * @Description 根据pageID来查找元素集合
     */
    @Override
    public List<AppElement> selectAppElementListByPageID(Long pageID) {
        return appElementMapper.selectAppElementListByPageID(pageID);
    }

    /**
     * @param elementType
     * @return java.util.List<com.tao.pojo.AppElement>
     * @Description 根据类型来查找元素集合
     */
    @Override
    public List<AppElement> selectAppElementListByType(Long elementType) {
        return appElementMapper.selectAppElementListByType(elementType);
    }

    /**
     * @param appElement 当appElement属性为空时，则返回所有元素
     * @return java.util.List<com.tao.pojo.AppElement>
     * @Description 根据appElement查找元素列表
     */
    @Override
    public List<AppElement> selectAppElementList(AppElement appElement) {
        return appElementMapper.selectAppElementList(appElement);
    }

    /**
     * @param appElement
     * @return java.util.List<com.tao.pojo.AppElement>
     * @Description 根据字符属性字段模糊查找元素集合
     */
    @Override
    public List<AppElement> selectAppElementListFuzzy(AppElement appElement) {
        return appElementMapper.selectAppElementListFuzzy(appElement);
    }

    /**
     * @param appElement
     * @return int
     * @Description 插入元素
     */
    @Override
    public int insertAppElement(AppElement appElement) {
        return appElementMapper.insertAppElement(appElement);
    }

    /**
     * @param appElement
     * @return int
     * @Description 更新元素
     */
    @Override
    public int updateAppElement(AppElement appElement) {
        return appElementMapper.updateAppElement(appElement);
    }

    /**
     * @param id
     * @return int
     * @Description 根据ID删除元素
     */
    @Override
    public int deleteAppElementById(Long id) {
        return appElementMapper.deleteAppElementById(id);
    }

    /**
     * @param elementType
     * @return int
     * @Description 根据元素类型删除元素
     */
    @Override
    public int deleteAppElementByType(Long elementType) {
        return appElementMapper.deleteAppElementByType(elementType);
    }
}
