package ru.yandex.canvas.service.html5;

import java.io.IOException;
import java.io.StringWriter;
import java.net.URISyntaxException;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;

import ru.yandex.canvas.service.SessionParams;

public class Preview {

    private final List<List<String>> htmlReplacements;
    private final String html5File;
    private final String nonce;
    private final Set<String> features;
    private final SessionParams.Html5Tag productType;

    private DataParams properties;
    private final boolean closeButtonIsPresent;
    private static final String DEFAULT_CLICK_URL = "javascript:void(0)";

    public Preview(List<List<String>> source, String html5File, boolean closeButtonIsPresent, Set<String> features,
                   SessionParams.Html5Tag productType) {
        this(source, html5File, null, "", closeButtonIsPresent, features, productType);
    }

    public Preview(List<List<String>> htmlReplacements, String html5File, DataParams properties, String nonce,
                   boolean closeButtonIsPresent, Set<String> features, SessionParams.Html5Tag productType) {
        this.htmlReplacements = htmlReplacements;
        this.html5File = html5File;
        this.properties = properties;
        this.nonce = nonce;
        this.closeButtonIsPresent = closeButtonIsPresent;
        this.features = features;
        this.productType = productType;

        //see https://st.yandex-team.ru/PCODE-5895 for format description

        if (properties == null) {
            this.properties = DataParams.defaultDataParams();
        }
    }

    public String asHtml(Integer width, Integer height, String basePath) throws IOException, URISyntaxException {
        String rtbHtml =
                new RtbhostedHtml(html5File, htmlReplacements, features, productType).getPreview(properties.toJson());

        Mustache mustache = new DefaultMustacheFactory().compile("html5_preview_template.html");
        Map<String, Object> params = new HashMap<>();

        Map<String, String> settings;

        if (features.contains("social_advertising")) {
            settings = Map.of("bannerFlags", "social_advertising");
        } else {
            settings = Map.of();
        }

        params.put("data", new RtbData(width, height, basePath, rtbHtml, closeButtonIsPresent, settings).toJson());
        params.put("nonce", nonce);

        StringWriter writer = new StringWriter();
        mustache.execute(writer, params);
        writer.flush();

        return writer.toString();
    }

    public static class RtbData {

        @JsonProperty("rtb")
        Rtb rtb;

        @JsonProperty("common")
        Common common;

        @JsonProperty("settings")
        Map<String, Map<String, String>> settings;

        public RtbData(Integer width, Integer height, String basePath, String rtbHtml,
                       boolean abuseLinkPresent, Map<String, String> settings) {
            rtb = new Rtb();
            rtb.html = Base64.getUrlEncoder().encodeToString(rtbHtml.getBytes());
            rtb.width = width;
            rtb.height = height;
            rtb.html5 = "true";
            rtb.basePath = basePath;
            rtb.abuseLink = abuseLinkPresent ? DEFAULT_CLICK_URL : null;

            this.settings = Map.of("1", settings);

            common = new Common();
            common.isYandex = "1";
            common.reloadTimeout = "1";
        }

        public String toJson() throws JsonProcessingException {
            return new ObjectMapper().writeValueAsString(this);
        }

        public static class Rtb {

            @JsonProperty("html")
            String html;
            @JsonProperty("width")
            Integer width;
            @JsonProperty("height")
            Integer height;
            @JsonProperty("html5")
            String html5;
            @JsonProperty("basePath")
            String basePath;
            @JsonProperty("abuseLink")
            String abuseLink;

            private Rtb() {
            }
        }

        public static class Common {

            @JsonProperty("isYandex")
            String isYandex;

            @JsonProperty("reloadTimeout")
            String reloadTimeout;

            private Common() {
            }
        }
    }

    public static class DataParams {
        @JsonProperty("data_params")
        Map<Long, UrlData> dataParams;

        public static DataParams defaultDataParams() {
            //see https://st.yandex-team.ru/PCODE-5895 for format description

            var properties = new DataParams();
            properties.addRecord(1L);

            properties
                    .getRecord(1L)
                    .getClickUrls()
                    .setClickUrl1(DEFAULT_CLICK_URL)
                    .setClickUrl2(DEFAULT_CLICK_URL)
                    .setClickUrl3(DEFAULT_CLICK_URL);

            return properties;
        }

        public DataParams() {
            dataParams = new HashMap<>();
        }

        public String toJson() {
            try {
                return new ObjectMapper().writeValueAsString(this);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }

        public void addRecord(long id) {
            dataParams.put(id, new UrlData());
        }

        public void addRecord(long id, UrlData urlData) {
            dataParams.put(id, urlData);
        }

        public UrlData getRecord(long id) {
            return dataParams.get(id);
        }

    }

}
