package com.zhiqiyun.open.core.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhiqiyun.open.core.mapper.sentiment.SentimentSpiderEventMapper;
import com.zhiqiyun.open.core.models.sentiment.SentimentSpiderEvent;
import com.zhiqiyun.open.core.models.sentiment.SentimentSpiderSiteRule;
import com.zhiqiyun.open.core.service.SentimentSpiderEventService;
import com.zhiqiyun.open.core.service.SentimentSpiderResultService;
import com.zhiqiyun.open.core.spiders.HtmlPageProcessor;
import com.zhiqiyun.open.core.spiders.SpiderEventPipeline;
import com.zhiqiyun.open.core.spiders.WeiboPageProcessor;
import com.zhiqiyun.open.core.spiders.WeiboPipeline;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.downloader.Downloader;
import us.codecraft.webmagic.pipeline.Pipeline;
import us.codecraft.webmagic.processor.PageProcessor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class SentimentSpiderEventServiceImpl extends ServiceImpl<SentimentSpiderEventMapper, SentimentSpiderEvent> implements SentimentSpiderEventService, ApplicationContextAware {

    private static final ConcurrentHashMap<Long, Spider> SPIDER_RUNNING_MAP = new ConcurrentHashMap<>();

    @Autowired
    private SentimentSpiderResultService sentimentSpiderResultService;

    private ApplicationContext applicationContext;


    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void start(SentimentSpiderEvent event) {

        SentimentSpiderSiteRule rule = event.getRule();
        if (rule == null || StringUtils.isBlank(event.getKeywords()) || StringUtils.isBlank(rule.getStartUrls())) {
            return;
        }
        String[] urlArray = rule.getStartUrls().split("\n");

        PageProcessor processor;
        Pipeline pipeline;
        String[] keywords = event.getKeywords().split(",");
        if ("weibo".equals(rule.getCollectorName())) {
            processor = new WeiboPageProcessor(rule);
            pipeline = new WeiboPipeline(keywords, event.getId(), event.getSiteRuleId(), this.sentimentSpiderResultService);
        } else {
            processor = new HtmlPageProcessor(rule);
            pipeline = new SpiderEventPipeline(keywords, event.getId(), event.getSiteRuleId(), this.sentimentSpiderResultService);
        }

        Spider spider = Spider.create(processor);
        List<Pipeline> pipelines = new ArrayList<>();

        pipelines.add(pipeline);
        spider.setPipelines(pipelines);
        spider.setExitWhenComplete(true);
        if (!Arrays.asList("html", "weibo").contains(rule.getCollectorName())) {
            String beanName = String.format("%s.downloader", rule.getCollectorName());
            Downloader downloader = this.applicationContext.getBean(beanName, Downloader.class);
            spider.setDownloader(downloader);
        }
        spider.addUrl(urlArray);
        spider.runAsync();

        SPIDER_RUNNING_MAP.put(event.getId(), spider);
    }

    @Override
    public void stop(SentimentSpiderEvent event) {
        Spider spider = SPIDER_RUNNING_MAP.get(event.getId());
        if (spider != null && spider.getStatus().equals(Spider.Status.Running)) {
            spider.stop();
        }
    }

    @Override
    public int getStatus(Long eventId) {
        Spider spider = SPIDER_RUNNING_MAP.get(eventId);
        if (spider == null) {
            return 0;
        } else if (spider.getStatus().equals(Spider.Status.Running)) {
            return 1;
        } else if (spider.getStatus().equals(Spider.Status.Stopped)) {
            return 2;
        } else {
            return 0;
        }
    }


//    public static class SpiderEventProcessor implements PageProcessor {
//        private final List<String> LIST_SPIDER_URLS = new ArrayList<>();
//
//        private final Site site;
//
//        private final SentimentSpiderSiteRule rule;
//
//
//        public SpiderEventProcessor(SentimentSpiderSiteRule rule) {
//            this.rule = rule;
//            this.site = Site.me();
//            this.site.setUseGzip(true);
//            this.site.setRetryTimes(3);
//            this.site.setSleepTime(1000);
//        }
//
//        @Override
//        public void process(Page page) {
//            List<String> listUrls = page.getHtml().links().all();
//
//            listUrls.removeIf(url -> StringUtils.isBlank(url) || LIST_SPIDER_URLS.contains(url));
//
//            List<UrlPatterns> listUrlPatterns = this.rule.getUrlPatterns();
//
//            AtomicReference<UrlPatterns> matchedUrlPattern = new AtomicReference<>(null);
//            if (listUrlPatterns != null) {
//                listUrls.removeIf(url -> {
//                    log.info(url);
//                    boolean hasMatched = false;
//                    for (UrlPatterns urlPattern : listUrlPatterns) {
//                        hasMatched = Pattern.matches(urlPattern.getUrlPattern(), url);
//                        if (hasMatched) {
//                            break;
//                        }
//                    }
//                    return !hasMatched;
//                });
//
//                for (UrlPatterns urlPattern : listUrlPatterns) {
//                    if (Pattern.matches(urlPattern.getUrlPattern(), page.getUrl().get())) {
//                        matchedUrlPattern.set(urlPattern);
//                    }
//                }
//            }
//
//            LIST_SPIDER_URLS.addAll(listUrls);
//
//            page.addTargetRequests(listUrls);
//
//            Document document = page.getHtml().getDocument();
//
//            String title = document.title();
//            String bodyText = "";
//            String html = document.html();
//
//            String keywords = "";
//            String description = "";
//            Elements elements = document.getElementsByTag("meta");
//
//            if (elements != null && elements.size() > 0) {
//                for (Element element : elements) {
//                    String metaName = element.attr("name");
//                    String metaContent = element.attr("content");
//                    if (StringUtils.equalsIgnoreCase("keywords", metaName)) {
//                        keywords = metaContent;
//                    }
//                    if (StringUtils.equalsIgnoreCase("description", metaName)) {
//                        description = metaContent;
//                    }
//                }
//            }
//            Selectable selectable;
//            UrlPatterns urlPatterns = null;
//            if (matchedUrlPattern.get() != null) {
//                urlPatterns = matchedUrlPattern.get();
//            }
//
//            if (urlPatterns == null) {
//                selectable = page.getHtml();
//            } else if ("XpathSelector".equals(urlPatterns.getSelectorName())) {
//                XpathSelector xpathSelector = new XpathSelector(urlPatterns.getSelectorText());
//                selectable = page.getHtml().select(xpathSelector);
//            } else if ("CssSelector".equals(urlPatterns.getSelectorName())) {
//                CssSelector cssSelector = new CssSelector(urlPatterns.getSelectorText());
//                selectable = page.getHtml().select(cssSelector);
//            } else {
//                selectable = page.getHtml();
//            }
//
//            List<String> listFragments = new ArrayList<>();
//            if (selectable.match()) {
//                document.html(selectable.get());
//                bodyText = document.text();
//
//                Elements allElements = document.children().first().children();
//                for (Element element : allElements) {
//                    String text = element.text();
//                    if (StringUtils.isNotBlank(text)) {
//                        listFragments.add(text.trim());
//                    }
//                }
//            }
//
//            log.info("{}>>>>>>>>{}>>>>>>>>{}", page.getUrl(), listFragments.size(), bodyText);
//
//            if (StringUtils.isBlank(bodyText)) {
//                page.setSkip(true);
//            }
//
//
//            if (StringUtils.isBlank(description) && StringUtils.isNotBlank(bodyText)) {
//                description = bodyText.length() >= 200 ? bodyText.substring(0, 200) : bodyText;
//            }
//
//            if (StringUtils.isBlank(keywords) && StringUtils.isNotBlank(description)) {
//                keywords = description;
//            }
//
//            page.putField("title", title);
//            page.putField("bodyText", bodyText);
//            page.putField("html", html);
//            page.putField("keywords", keywords);
//            page.putField("description", description);
//            page.putField("listFragments", JSON.toJSONString(listFragments));
//        }
//
//        @Override
//        public Site getSite() {
//            return this.site;
//        }
//    }
}
