package com.tarpha.torrssen2.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import com.tarpha.torrssen2.domain.RssFeed;
import com.tarpha.torrssen2.domain.RssList;
import com.tarpha.torrssen2.domain.Setting;
import com.tarpha.torrssen2.repository.RssListRepository;
import com.tarpha.torrssen2.repository.SettingRepository;

import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

@Service
@Slf4j
public class RssMakeService {

    @Value("${internal-rss1.base-url}")
    private String baseUrl1;

    @Value("${internal-rss1.page-query}")
    private String pageQuery1;

    @Value("${internal-rss1.max-page}")
    private int maxPage1;

    @Value("${internal-rss1.board-query}")
    private String boardQuery1;

    @Value("${internal-rss2.base-url}")
    private String baseUrl2;

    @Value("${internal-rss2.page-html}")
    private String pageHtml2;

    @Value("${internal-rss2.max-page}")
    private int maxPage2;

    // @Value("${internal-rss1.tv-boards}")
    // private String[] tvBoards1;

    @Value("${internal-rss2.tv-boards}")
    private String[] tvBoards2;

    // @Value("${internal-rss.other-boards}")
    // private String[] otherBoards;

    @Autowired
    private SettingRepository settingRepository;

    @Autowired
    private RssListRepository rssListRepository;

    @Autowired
    private DaumMovieTvService daumMovieTvService;

    private final int TIMEOUT_VALUE = 30000;

    public List<RssFeed> makeRss() {
        List<RssFeed> rssFeedList = new ArrayList<>();

        for (RssList rss : rssListRepository.findByUseDbAndInternal(true, true)) {
            rssFeedList.addAll(makeRss1(rss));
            rssFeedList.addAll(makeRss2(rss));
        }

        return rssFeedList;
    }

    private List<RssFeed> makeRss1(RssList rss) {
        log.info("Load RSS Site1 : " + rss.getName());
        
        List<RssFeed> rssFeedList = new ArrayList<>();

        for(int page = 1; page <= maxPage1; page++ ) {
            String url = baseUrl1 + "?" + boardQuery1 + "=" + rss.getUrl() + "&" + pageQuery1 + "=" + page;
            Document doc = getDoc(url);
            Elements els = null;
            
            try {
                els = doc.select(".board-list-body table tr td .td-subject");
                
                for(int i = els.size() -1; i >= 0; i--) {
                    try {
                        Element item = els.get(i).select("a").last();
                        String title = item.text();
                        String magnet = getMagnetString1(item.absUrl("href"));
                        log.debug(title + "|" + magnet);

                        rssFeedList.add(makeFeed(title, magnet, rss));
                    } catch (Exception e) {
                        log.error(els.get(i).select("a").last().text() + "/" + e.toString());
                    }
                }

            } catch (NullPointerException e) {
                log.error(baseUrl1 + " / " + e.toString());
            }
        }

        return rssFeedList;
    }

    private List<RssFeed> makeRss2(RssList rss) {
        log.info("Load RSS Site2 : " + rss.getName());

        List<RssFeed> rssFeedList = new ArrayList<>();

        for(int page = 1; page <= maxPage2; page++ ) {
            String targetBoard = null;

            for(int i = 0; i < tvBoards2.length; i++) {
                if(StringUtils.equals(tvBoards2[i], rss.getUrl())) {
                    targetBoard = tvBoards2[i];
                }
            }

            if(StringUtils.isBlank(targetBoard)) {
                return rssFeedList;
            }

            String url = baseUrl2 + "/" + targetBoard + "/list?p&" + pageHtml2 + "=" + page;
            log.info(url);
            Document doc = getDoc(url);

            Elements els = null;
            
            try {
                els = doc.select("script");

                for(int i = els.size() -1; i >= 0; i--) {
                    Pattern pattern = Pattern.compile(".*pageItems\\s*=\\s*(\\[.*\\]).*", Pattern.CASE_INSENSITIVE);
                    Matcher matcher = pattern.matcher(els.get(i).toString());

                    if (matcher.matches()) {
                        JSONArray jsonArray = new JSONArray(matcher.group(1));

                       for(int j = 0; j < jsonArray.length(); j++) {
                           JSONObject jsonObj = jsonArray.getJSONObject(j);
                           String title = jsonObj.getString("fn");
                           String magnet = "magnet:?xt=urn:btih:" + jsonObj.getString("hs");

                           rssFeedList.add(makeFeed(title, magnet, rss));
                       }

                    }
                }

            } catch ( NullPointerException e) {
                log.error(baseUrl2 + " / " + e.toString());
            }
        }

        return rssFeedList;
    }

    private RssFeed makeFeed(String title, String magnet, RssList rss) {
        RssFeed rssFeed = new RssFeed();
        rssFeed.setTitle(title);
        rssFeed.setRssSite(rss.getName());
        rssFeed.setLink(magnet);
        rssFeed.setTvSeries(rss.getTvSeries());
        rssFeed.setRssTitleByTitle(title);
        rssFeed.setRssEpisodeByTitle(title);
        rssFeed.setRssSeasonByTitle(title);
        rssFeed.setRssQualityBytitle(title);
        rssFeed.setRssReleaseGroupByTitle(title);
        rssFeed.setRssDateBytitle(title);

        String[] rssTitleSplit = StringUtils.split(rssFeed.getRssTitle());
        if (rssTitleSplit.length == 1) {
            rssFeed.setRssPoster(daumMovieTvService.getPoster(rssFeed.getRssTitle()));
        } else {
            for (int j = rssTitleSplit.length - 1; j > 0; j--) {
                StringBuffer posterTitle = new StringBuffer();
                for (int k = 0; k <= j; k++) {
                    posterTitle.append(rssTitleSplit[k] + " ");
                }
                String posterUrl = daumMovieTvService
                        .getPoster(StringUtils.trim(posterTitle.toString()));
                if (!StringUtils.isEmpty(posterUrl)) {
                    rssFeed.setRssPoster(posterUrl);
                    break;
                }
            }
        }

        return rssFeed;
    }

    private Document getDoc(String urlString) {
        URL url;
        HttpsURLConnection uc = null;

        try {
            url = new URL(urlString);

            Optional<Setting> optionalHost = settingRepository.findByKey("PROXY_HOST");
            Optional<Setting> optionalPort = settingRepository.findByKey("PROXY_PORT");

            TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                    public void checkClientTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(
                        java.security.cert.X509Certificate[] certs, String authType) {
                    }
                }
            };
            
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

            if (optionalHost.isPresent() && optionalPort.isPresent()) {
                log.debug("Use Proxy");
                String proxyHost = optionalHost.get().getValue();
                int proxyPort = Integer.parseInt(optionalPort.get().getValue());

                Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
                uc = (HttpsURLConnection)url.openConnection(proxy);
                uc.setConnectTimeout(TIMEOUT_VALUE);
                uc.setReadTimeout(TIMEOUT_VALUE);
                uc.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.13) Gecko/20150702 Firefox/3.6.13 (.NET CLR 3.5.30729)");

                uc.connect();

                String line = null;
                StringBuffer tmp = new StringBuffer();
                BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
                
                while ((line = in.readLine()) != null) {
                    tmp.append(line);
                }

                in.close();
                uc.disconnect();

                return Jsoup.parse(String.valueOf(tmp));
            } else {
                log.debug("No Proxy");
                return Jsoup.connect(urlString).get();
            }
        } catch(Exception e) {
            log.error(urlString + " / " + e.toString());
            return null;
        } finally {
            if(uc != null) uc.disconnect();
        }
        
    }

    private String getMagnetString1(String urlString) throws Exception {
        Document doc = getDoc(urlString);

        Element el = doc.selectFirst(".btn.btn-success.btn-xs");

        Pattern pattern = Pattern.compile("magnet_link\\(\\'(.{1,})\\'\\);", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(el.attr("onclick"));

        if (matcher.matches()) {
            return "magnet:?xt=urn:btih:" + matcher.group(1);
        } else {
            return null;
        }
    }

    // private String getMagnetString2(String urlString) throws Exception {
    //     Document doc = getDoc(urlString);
    //     Element el = doc.selectFirst("div + b + a");

    //     return el.attr("href");
    // }
    
}