package ru.yandex.canvas;

import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

import ru.yandex.canvas.model.Size;
import ru.yandex.canvas.model.video.addition.RtbStatus;
import ru.yandex.canvas.service.SessionParams;
import ru.yandex.canvas.service.html5.Html5Preset;

import static ru.yandex.canvas.service.SessionParams.SessionTag.CPM_BANNER;
import static ru.yandex.canvas.service.SessionParams.SessionTag.CPM_GEOPRODUCT;
import static ru.yandex.canvas.service.SessionParams.SessionTag.CPM_PRICE;
import static ru.yandex.canvas.service.SessionParams.SessionTag.CPM_YNDX_FRONTPAGE;
import static ru.yandex.canvas.service.SessionParams.SessionTag.GENERATOR;
import static ru.yandex.canvas.service.SessionParams.SessionTag.PLAYABLE;

public class Html5Constants {
    public static final String IMAGE_HTML_TEMPLATE_PATH = "image_html_template.html";
    public static final Long MAX_FILE_SIZE = 250 * 1024L;
    public static final Long MAX_CPM_BANNER_FILE_SIZE = 512 * 1024L;
    public static final Long DEFAULT_MAX_FILE_SIZE = 150 * 1024L;
    public static final Long FRONTPAGE_MAX_FILE_SIZE = 1024L * 1024L;
    public static final Long MAX_CPM_PRICE_VIDEO_FILE_SIZE = 20 * 1024 * 1024L;//размер zip для расхлопа
    public static final Long MAX_FILES_COUNT = 20L;
    public static final Long IMAGE_COUNT_MERGE_TO_SPRITE = 3L;

    public static final Long DEFAULT_MAX_HTML_FILE_SIZE = 500 * 1024L;
    public static final Long HTML5_VIDEO_ALLOWED_FILE_SIZE = 3 * 1024L * 1024L;
    public static final Long PLAYABLE_ALLOWED_FILE_SIZE = 3 * 1024L * 1024L;
    public static final Long GENERATOR_ALLOWED_FILE_SIZE = 3 * 1024L * 1024L;
    public static final String HTML5_VIDEO_ALLOWED_FEATURE = "html5_video_allowed";
    public static final String HTML5_VIDEO_MUTE_FEATURE = "html5_video_mute";
    public static final String HTML5_ASYNC_INSPECTION_FEATURE = "html5_async_inspection";
    public static final String HTML5_EXTERNAL_REQUESTS_SKIP_INSPECTION_FEATURE =
            "agency_skip_html5_external_requests_inspection";
    public static final String NEW_LIVE_PREVIEW_URL_FOR_HTML5_CREATIVES_ENABLED_FEATURE =
            "new_live_preview_url_for_html5_creatives_enabled";
    public static final String NEW_SCREENSHOT_URL_FOR_HTML5_CREATIVES_ENABLED_FEATURE =
            "new_screenshot_url_for_html5_creatives_enabled";

    public static final Map<SessionParams.Html5Tag, Long> MAX_HTML_FILE_SIZE_BY_TAG = Map.of(
            SessionParams.Html5Tag.HTML5_CPM_YNDX_FRONTPAGE, 150 * 1024L,
            SessionParams.Html5Tag.CPM_PRICE, 150 * 1024L,
            SessionParams.Html5Tag.PLAYABLE, PLAYABLE_ALLOWED_FILE_SIZE,
            SessionParams.Html5Tag.GENERATOR, GENERATOR_ALLOWED_FILE_SIZE
    );

    //теги для креативов на главной странице яндекса
    public static final Set<SessionParams.Html5Tag> FRONTPAGE_TAGS =
            ImmutableSet.of(SessionParams.Html5Tag.HTML5_CPM_YNDX_FRONTPAGE, SessionParams.Html5Tag.CPM_PRICE);
    /**
     * Разрешенные к загрузке типы изображений
     */
    public static final Set<String> VALID_IMAGE_EXTENSIONS = ImmutableSet.of("gif", "jpg", "jpeg", "png");

    public static final Set<String> VALID_VIDEO_EXTENSIONS = ImmutableSet.of("mp4");
    public static final Double MAX_VIDEO_DURATION = 5. * 60.;//Максимальная продолжительность видеоролика — 5 минут

    public static final Map<String, String> VALID_IMAGE_MIME_TYPES = ImmutableMap.of("image/gif", "gif",
            "image/jpeg", "jpg",
            "image/png", "png");

    public static final Set<String> ALLOWED_HTML_EXTENSIONS = ImmutableSet.of("htm", "html");

    public static final Set<String> ALLOWED_FILE_EXTENSIONS = ImmutableSet.<String>builder()
            .addAll(ALLOWED_HTML_EXTENSIONS)
            .addAll(VALID_IMAGE_EXTENSIONS)
            .add("js")
            .add("json")
            .add("css")
            .add("svg")
            .build();

    public static final Set<String> ALLOWED_CPM_PRICE_FILE_EXTENSIONS = ImmutableSet.<String>builder()
            .addAll(ALLOWED_FILE_EXTENSIONS)
            .addAll(VALID_VIDEO_EXTENSIONS)
            .build();

    public static final Set<SessionParams.SessionTag> IS_ZIP_UPLOADING_SUPPORTED =
            ImmutableSet.of(CPM_BANNER, CPM_YNDX_FRONTPAGE, CPM_PRICE, PLAYABLE, GENERATOR);

    public static final Set<SessionParams.Html5Tag> IS_INLINE_EVENT_HANDLERS_FORBIDDEN =
            ImmutableSet.of(SessionParams.Html5Tag.HTML5_CPM_YNDX_FRONTPAGE, SessionParams.Html5Tag.CPM_PRICE);

    /**
     * Размеры баннеров, валидные для обычного конструктора
     */

    private final static Html5Preset PRESET_728x90 = new Html5Preset(10, Size.of(728, 90));
    private final static Html5Preset PRESET_1456x180 = new Html5Preset(16, Size.of(728 * 2, 90 * 2));
    private final static Html5Preset PRESET_640x134 = new Html5Preset(17, Size.of(320 * 2, 67 * 2));

    //1836x572
    private final static Html5Preset PRESET_1836x572 = new Html5Preset(18, Size.of(1836, 572));
    public static final Set<Html5Preset> PREMIUM_MOBILE = Set.of(new Html5Preset(19, Size.of(640, 268)),
            new Html5Preset(20, Size.of(640, 335)));//мобильный премиум
    public static final Set<Html5Preset> PREMIUM_FORMATS = ImmutableSet.<Html5Preset>builder()
            .add(PRESET_1836x572)
            .addAll(PREMIUM_MOBILE)
            .build();

    public static final Set<Html5Preset> GENERAL_HTML5_PRESETS = ImmutableSet
            .<Html5Preset>builder()
            .add(new Html5Preset(1, Size.of(240, 400)))
            .add(new Html5Preset(2, Size.of(240, 600)))
            .add(new Html5Preset(3, Size.of(300, 250)))
            .add(new Html5Preset(4, Size.of(300, 500)))
            .add(new Html5Preset(5, Size.of(300, 600)))
            .add(new Html5Preset(6, Size.of(336, 280)))
            .add(new Html5Preset(7, Size.of(320, 50)))
            .add(new Html5Preset(8, Size.of(320, 100)))
            .add(new Html5Preset(9, Size.of(320, 480)))
            .add(PRESET_728x90)
            .add(new Html5Preset(11, Size.of(480, 320)))
            .add(new Html5Preset(12, Size.of(970, 250)))
            .add(new Html5Preset(13, Size.of(1000, 120)))
            .add(new Html5Preset(14, Size.of(300, 300)))
            .add(new Html5Preset(15, Size.of(160, 600)))
            .build();

    public static final Set<Size> VALID_SIZES_GENERAL =
            GENERAL_HTML5_PRESETS.stream().map(Html5Preset::getSize).collect(Collectors.toSet());

    public static final Set<Html5Preset> PRESETS_MARKET = ImmutableSet
            .<Html5Preset>builder()
            .add(new Html5Preset(35, Size.of(0, 120)))
            .add(new Html5Preset(36, Size.of(0, 150)))
            .build();
    public static final Set<Size> VALID_SIZES_MARKET = PRESETS_MARKET.stream()
            .map(Html5Preset::getSize).collect(Collectors.toSet());


    /**
     * Размеры баннеров, валидные для конструктора для Медийного продукта на Главной
     */

    public static final Set<Html5Preset> PRESETS_CPM_YNDX_FRONTPAGE = ImmutableSet.of(
            PRESET_1456x180, PRESET_640x134);

    public static final Set<Size> VALID_SIZES_CPM_YNDX_FRONTPAGE =
            PRESETS_CPM_YNDX_FRONTPAGE.stream().map(Html5Preset::getSize).collect(Collectors.toSet());

    /**
     * Размеры баннеров, валидные для конструктора для Прайсовых продуктов
     */

    private static final Html5Preset PRESET_2000x250 = new Html5Preset(24, Size.of(2000, 250));
    private static final Html5Preset PRESET_2560x1600 = new Html5Preset(30, Size.of(2560, 1600));

    /**
     * Временное решение для перетяжек. С шириной 0 слишком много костылей.
     * Поэтому решили занять пока для перетяжек ширину в 1900px.
     * Правильное решение нужно будет придумать тут https://st.yandex-team.ru/DIRECT-148786
     */
    private static final Html5Preset PRESET_0x50 = new Html5Preset(38, Size.of(1900, 50));
    private static final Html5Preset PRESET_0x90 = new Html5Preset(31, Size.of(1900, 90));
    private static final Html5Preset PRESET_0x150 = new Html5Preset(32, Size.of(1900, 150));
    private static final Html5Preset PRESET_0x180 = new Html5Preset(33, Size.of(1900, 180));
    private static final Html5Preset PRESET_0x250 = new Html5Preset(34, Size.of(1900, 250));

    public static final Set<Html5Preset> EXTRA_PRESETS_CPM_PRICE = ImmutableSet.of(
            new Html5Preset(23, Size.of(1440, 250)),
            PRESET_2000x250,
            new Html5Preset(25, Size.of(300, 900)),
            new Html5Preset(26, Size.of(880, 90)),
            new Html5Preset(27, Size.of(1180, 520)),
            new Html5Preset(28, Size.of(540, 180)),
            new Html5Preset(29, Size.of(1440, 90)),
            new Html5Preset(37, Size.of(0, 50)),
            PRESET_2560x1600);

    public static final Set<Html5Preset> EXTRA_STRETCHABLE_PRESETS_CPM_PRICE = ImmutableSet.of(
            PRESET_0x50,
            PRESET_0x90,
            PRESET_0x150,
            PRESET_0x180,
            PRESET_0x250);

    /**
     * Размеры баннеров, валидные для конструктора для прайсовых продуктов на Главной
     */
    public static final Set<Html5Preset> PRESETS_CPM_PRICE = ImmutableSet.<Html5Preset>builder()
            .add(PRESET_640x134)
            .add(PRESET_1456x180)
            .addAll(PREMIUM_FORMATS)
            .build();

    public static final Set<Size> VALID_SIZES_CPM_PRICE =
            PRESETS_CPM_PRICE.stream().map(Html5Preset::getSize).collect(Collectors.toSet());

    /**
     * Размеры баннеров, валидные для конструктора для Геопродукта
     */
    private static final Set<Html5Preset> PRESETS_CPM_GEOPRODUCT = ImmutableSet.of(
            new Html5Preset(22, Size.of(640, 100)));

    private static final Set<Size> VALID_SIZES_CPM_GEOPRODUCT =
            PRESETS_CPM_GEOPRODUCT.stream().map(Html5Preset::getSize).collect(Collectors.toSet());

    public enum Html5PresetType {
        GENERAL, FRONTPAGE, PRICE, GEOPRODUCT;

        @JsonValue
        public String getValue() {
            return name().toLowerCase();
        }

        @JsonCreator
        public static RtbStatus fromString(String name) {
            return RtbStatus.valueOf(name.toUpperCase(Locale.ROOT));
        }
    }

    public final static Map<Html5PresetType, Set<Html5Preset>> HTML5_PRESETS_BY_TYPE = Map.of(
            Html5PresetType.GENERAL,
            ImmutableSet.<Html5Preset>builder().addAll(GENERAL_HTML5_PRESETS).build(),
            Html5PresetType.FRONTPAGE,
            ImmutableSet.<Html5Preset>builder().addAll(PRESETS_CPM_YNDX_FRONTPAGE).build(),
            Html5PresetType.GEOPRODUCT,
            ImmutableSet.<Html5Preset>builder().addAll(PRESETS_CPM_GEOPRODUCT).build(),
            Html5PresetType.PRICE,
            ImmutableSet.<Html5Preset>builder().addAll(PRESETS_CPM_PRICE).addAll(EXTRA_PRESETS_CPM_PRICE).addAll(EXTRA_STRETCHABLE_PRESETS_CPM_PRICE).build()
    );


    public final static Set<Html5Preset> ALL_HTML5_PRESETS = ImmutableSet.<Html5Preset>builder()
            .addAll(GENERAL_HTML5_PRESETS)
            .addAll(PRESETS_CPM_YNDX_FRONTPAGE)
            .addAll(PRESETS_CPM_PRICE)
            .addAll(PRESETS_CPM_GEOPRODUCT)
            .addAll(EXTRA_PRESETS_CPM_PRICE)
            .addAll(EXTRA_STRETCHABLE_PRESETS_CPM_PRICE)
            .addAll(PRESETS_MARKET)
            .build();

    public final static Map<Integer, Html5Preset> HTML5_PRESETS_BY_ID = ALL_HTML5_PRESETS.stream()
            .collect(Collectors.toUnmodifiableMap(
                    Html5Preset::getId, Function.identity()
            ));

    public final static Map<Size, Html5Preset> HTML5_PRESETS_BY_SIZE = ALL_HTML5_PRESETS.stream()
            .collect(Collectors.toUnmodifiableMap(
                    Html5Preset::getSize, Function.identity()
            ));

    private static final Map<Html5Preset, Long> HTML5_PRESETS_CUSTOM_MAX_FILE_SIZES = ImmutableMap
            .<Html5Preset, Long>builder()
            .put(PRESET_2000x250, MAX_FILE_SIZE)
            .put(PRESET_2560x1600, MAX_FILE_SIZE)
            .put(PRESET_0x50, MAX_FILE_SIZE)
            .put(PRESET_0x90, MAX_FILE_SIZE)
            .put(PRESET_0x150, MAX_FILE_SIZE)
            .put(PRESET_0x180, MAX_FILE_SIZE)
            .put(PRESET_0x250, MAX_FILE_SIZE)
            .build();

    public static final Map<Html5Preset, Long> MAX_FILE_SIZE_BY_PRESET = ALL_HTML5_PRESETS.stream()
            .collect(Collectors.toUnmodifiableMap(
                    Function.identity(),
                    preset -> HTML5_PRESETS_CUSTOM_MAX_FILE_SIZES.getOrDefault(preset, DEFAULT_MAX_FILE_SIZE)));

    /**
     * Валидные размеры баннеров в конструкторе по продукту
     */
    public static final Map<SessionParams.SessionTag, Set<Size>> PRODUCT_VALID_SIZES = new ImmutableMap.Builder<SessionParams.SessionTag, Set<Size>>()
            .put(CPM_BANNER, VALID_SIZES_GENERAL)
            .put(GENERATOR, VALID_SIZES_GENERAL)
            .put(PLAYABLE, VALID_SIZES_GENERAL)
            .put(CPM_YNDX_FRONTPAGE, VALID_SIZES_CPM_YNDX_FRONTPAGE)
            .put(CPM_PRICE, VALID_SIZES_CPM_PRICE)
            .put(CPM_GEOPRODUCT, VALID_SIZES_CPM_GEOPRODUCT)
            .build();

    public static final String ADSDK_LIB = "https://awaps.yandex.net/data/lib/adsdk.js";

    public static final String CSS_CONTENT_TYPE = "text/css";

    private Html5Constants() {
    }
}
