package lan.dk.podcastserver.manager.worker.sixplay;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.TypeRef;
import com.mashape.unirest.http.HttpResponse;
import io.vavr.collection.List;
import io.vavr.control.Option;
import lan.dk.podcastserver.entity.Item;
import lan.dk.podcastserver.manager.downloader.DownloadingItem;
import lan.dk.podcastserver.manager.worker.Extractor;
import lan.dk.podcastserver.service.HtmlService;
import lan.dk.podcastserver.service.JsonService;
import lan.dk.podcastserver.service.M3U8Service;
import lan.dk.podcastserver.service.UrlService;
import lombok.*;
import org.jsoup.select.Elements;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import static io.vavr.API.Try;
import static org.springframework.beans.factory.config.ConfigurableBeanFactory.SCOPE_PROTOTYPE;

/**
 * Created by kevin on 26/12/2017
 */
@Component
@Scope(SCOPE_PROTOTYPE)
@RequiredArgsConstructor
public class SixPlayExtractor implements Extractor {

    private static final TypeRef<List<M6PlayItem>> TYPE_ITEMS = new TypeRef<List<M6PlayItem>>(){};
    private static final String ITEMS_EXTRACTOR = "video.currentVideo.clips[*]";

    private final HtmlService htmlService;
    private final JsonService jsonService;
    private final M3U8Service m3U8Service;
    private final UrlService urlService;

    @Override
    public DownloadingItem extract(Item item) {
        List<String> videos = htmlService.get(item.getUrl())
                .map(d -> d.select("script"))
                .map(this::extractUrl)
                .getOrElse(List::empty);

        return DownloadingItem.builder()
                .item(item)
                .urls(videos)
                .filename(getFileName(item))
                .build();
    }

    private List<String> extractUrl(Elements script) {
        return extractJson(script)
                .map(JsonService.to(ITEMS_EXTRACTOR, TYPE_ITEMS))
                .getOrElse(List::empty)
                .flatMap(this::keepBestQuality)
                .map(M6PlayAssets::getFull_physical_path);
    }

    private Option<DocumentContext> extractJson(Elements elements) {
        return SixPlayUpdater.getRoot6Play(elements).map(jsonService::parse);
    }

    private Option<M6PlayAssets> keepBestQuality(M6PlayItem item) {
        List<M6PlayAssets> assets = item.getAssets();

        return assets
                .filter(i -> !i.getFull_physical_path().contains("drmnp."))
                .find(i -> "sd3-ism".equalsIgnoreCase(i.getVideo_quality()))
                .flatMap(this::transformSd3Url)
                .orElse(() -> assets.find(i -> "usp_hls_h264".equalsIgnoreCase(i.getType())))
                .orElse(() -> assets.find(i -> "hq".equalsIgnoreCase(i.getVideo_quality())))
                .orElse(() -> assets.find(i -> "hd".equalsIgnoreCase(i.getVideo_quality())))
                .orElse(() -> assets.find(i -> "sd".equalsIgnoreCase(i.getVideo_quality())));
    }

    private Option<M6PlayAssets> transformSd3Url(M6PlayAssets asset) {
        String modifiedUrl = asset.getFull_physical_path().replaceAll("/([^/]+)\\.ism/[^/]*\\.m3u8", "/$1.ism/$1.m3u8");

        return Try(() -> urlService.get(modifiedUrl)
                .header(UrlService.USER_AGENT_KEY, UrlService.USER_AGENT_MOBILE)
                .asString())
                .map(HttpResponse::getRawBody)
                .flatMap(is -> m3U8Service.findBestQuality(is).toTry())
                .map(url -> urlService.addDomainIfRelative(modifiedUrl, url))
                .map(url -> new M6PlayAssets(asset.getVideo_quality(), url, asset.getType()))
                .toOption();
    }

    @Override
    public String getFileName(Item item) {
        return Extractor.super.getFileName(item) + ".mp4";
    }

    @Override
    public Integer compatibility(String url) {
        return SixPlayUpdater.isFrom6Play(url);
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    private static class M6PlayItem {
        @Getter @Setter private List<M6PlayAssets> assets;
    }

    @AllArgsConstructor @NoArgsConstructor
    @JsonIgnoreProperties(ignoreUnknown = true)
    private static class M6PlayAssets {
        @Setter @Getter private String video_quality;
        @Setter @Getter private String full_physical_path;
        @Setter @Getter private String type;
    }
}

@@ -669,16 +669,95 @@
 mbok.*;%0A
+import lombok.extern.slf4j.Slf4j;%0Aimport org.apache.commons.lang3.StringUtils;%0A
 import o
@@ -1055,16 +1055,23 @@
 017%0A */%0A
+@Slf4j%0A
 @Compone
@@ -2603,45 +2603,46 @@
 .get
-Full_physical_path().contains(%22drmnp.
+Protocol().equalsIgnoreCase(%22primetime
 %22))%0A
@@ -2672,34 +2672,28 @@
  -%3E 
-%22sd3-ism%22.equalsIgnoreCase
+StringUtils.contains
 (i.g
@@ -2709,16 +2709,23 @@
 uality()
+, %22sd3%22
 ))%0A     
@@ -3238,111 +3238,69 @@
 ing 
-modifiedUrl = asset.getFull_physical_path().replaceAll(%22/(%5B%5E/%5D+)%5C%5C.ism/%5B%5E/%5D*%5C%5C.m3u8%22, %22/$1.ism/$1.m3u8%22
+realURL = urlService.getRealURL(asset.getFull_physical_path()
 );%0A%0A
@@ -3339,27 +3339,23 @@
 ice.get(
-modifiedUrl
+realURL
 )%0A      
@@ -3640,19 +3640,15 @@
 ive(
-modifiedUrl
+realURL
 , ur
@@ -3742,16 +3742,37 @@
 etType()
+, asset.getProtocol()
 ))%0A     
@@ -4482,16 +4482,65 @@
 g type;%0A
+        @Setter @Getter private String protocol;%0A
     %7D%0A%7D%0A

handle token when working with 6play videos