package ru.yandex.canvas.service.video;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;

import com.typesafe.config.Config;
import com.typesafe.config.ConfigBeanFactory;
import com.typesafe.config.ConfigFactory;

import ru.yandex.canvas.service.AuthRequestParams;
import ru.yandex.canvas.service.DirectService;
import ru.yandex.canvas.service.VideoLimits;
import ru.yandex.canvas.service.VideoLimitsInterface;

public class VideoLimitsService {

    public static final String BASE_CONF_PATH = "video_configs/limits.conf";
    public static final String OUTDOOR_CONF_PATH = "video_configs/cpm_outdoor_limits.conf";

    private final VideoLimits defaultLimits;
    private final VideoLimits cpcLimits;
    private final VideoLimits cpmLimits;
    private final VideoLimits outdoorLimits;
    private final VideoLimits cpmYndxFrontpageLimits;
    private final VideoLimits mobileContentLimits;
    private final VideoLimits mobileContentVideoLimits;
    private final VideoLimits videoConstructorLimits;
    private final VideoLimits cpmAudioLimits;
    private final VideoLimits cpmAudio15SecLimits;
    private final VideoLimits cpmAudio30SecLimits;
    private final VideoLimits cpmAudio45SecLimits;
    private final VideoLimits longCpm;
    private final VideoLimits nonSkippableCpm15Seconds;
    private final VideoLimits nonSkippableCpm20Seconds;
    private final VideoLimits indoorLimits;

    private static final String LONG_VIDEO_FEATURE = "cpm_video_long_duration";
    private static final String UNRESTRICTED_NON_SKIPPABLE_VIDEO_FEATURE = "unrestricted_non_skippable_video";
    private final AuthRequestParams authRequestParams;
    private final DirectService directService;

    public VideoLimitsService(AuthRequestParams authRequestParams, DirectService directService) {
        this.authRequestParams = authRequestParams;
        this.directService = directService;

        Config baseConf = ConfigFactory.load(BASE_CONF_PATH).resolve();
        Config cpcConf = ConfigFactory.load("video_configs/cpc_limits.conf").withFallback(baseConf).resolve();
        Config cpmConf = ConfigFactory.load("video_configs/cpm_limits.conf").withFallback(baseConf).resolve();
        Config nonSkippableCpm15SecondsConf = ConfigFactory.load("video_configs/non_skippable_cpm_15_seconds_limits" +
                ".conf").withFallback(baseConf).resolve();
        Config nonSkippableCpm20SecondsConf = ConfigFactory.load("video_configs/non_skippable_cpm_20_seconds_limits" +
                ".conf").withFallback(baseConf).resolve();
        Config outdoorConf = ConfigFactory.load(OUTDOOR_CONF_PATH).withFallback(baseConf).resolve();
        Config cpmYndxFrontpageConf = ConfigFactory.load("video_configs/yndx_frontpage_limits.conf").withFallback(baseConf).resolve();
        Config indoorConf =
                ConfigFactory.load("video_configs/cpm_indoor_limits.conf").withFallback(baseConf).resolve();
        Config mobileContentConf =
                ConfigFactory.load("video_configs/mobile_content_limits.conf").withFallback(baseConf).resolve();
        Config mobileContentVideoConf =
                ConfigFactory.load("video_configs/mobile_content_video_limits.conf").withFallback(mobileContentConf).resolve();
        Config videoConstructorConf =
                ConfigFactory.load("video_configs/video_constructor_limits.conf").withFallback(baseConf).resolve();
        Config cpmAudioConf =
                ConfigFactory.load("video_configs/cpm_audio_limits.conf").withFallback(baseConf).resolve();
        Config cpmAudio15SecConf =
                ConfigFactory.load("video_configs/cpm_audio_15_sec_limits.conf").withFallback(cpmAudioConf).resolve();
        Config cpmAudio30SecConf =
                ConfigFactory.load("video_configs/cpm_audio_30_sec_limits.conf").withFallback(cpmAudioConf).resolve();
        Config cpmAudio45SecConf =
                ConfigFactory.load("video_configs/cpm_audio_45_sec_limits.conf").withFallback(cpmAudioConf).resolve();
        defaultLimits = ConfigBeanFactory.create(baseConf, VideoLimits.class);
        cpcLimits = ConfigBeanFactory.create(cpcConf, VideoLimits.class);
        cpmLimits = ConfigBeanFactory.create(cpmConf, VideoLimits.class);
        longCpm = ConfigBeanFactory.create(cpmConf, VideoLimits.class);
        nonSkippableCpm15Seconds = ConfigBeanFactory.create(nonSkippableCpm15SecondsConf, VideoLimits.class);
        nonSkippableCpm20Seconds = ConfigBeanFactory.create(nonSkippableCpm20SecondsConf, VideoLimits.class);
        outdoorLimits = ConfigBeanFactory.create(outdoorConf, VideoLimits.class);
        cpmYndxFrontpageLimits = ConfigBeanFactory.create(cpmYndxFrontpageConf, VideoLimits.class);
        mobileContentLimits = ConfigBeanFactory.create(mobileContentConf, VideoLimits.class);
        mobileContentVideoLimits = ConfigBeanFactory.create(mobileContentVideoConf, VideoLimits.class);
        videoConstructorLimits = ConfigBeanFactory.create(videoConstructorConf, VideoLimits.class);
        cpmAudioLimits = ConfigBeanFactory.create(cpmAudioConf, VideoLimits.class);
        cpmAudio15SecLimits = ConfigBeanFactory.create(cpmAudio15SecConf, VideoLimits.class);
        cpmAudio30SecLimits = ConfigBeanFactory.create(cpmAudio30SecConf, VideoLimits.class);
        cpmAudio45SecLimits = ConfigBeanFactory.create(cpmAudio45SecConf, VideoLimits.class);
        indoorLimits = ConfigBeanFactory.create(indoorConf, VideoLimits.class);
        longCpm.setDurationMax(120.0);
        longCpm.setDurationCaptureStop(120.0);
    }

    public VideoLimitsInterface getLimits(VideoCreativeType videoCreativeType, Long presetId) {
        //Не всегда есть возможность получить фичи и пользователя из authRequestParams.
        // Для фоновых операций лучше их явно передать
        Set<String> features = directService.getFeatures(authRequestParams.getClientId().orElse(null),
                authRequestParams.getUserId().orElse(null));
        return getLimits(videoCreativeType, features, presetId);
    }

    public List<String> getRatiosByVideoCreativeType(VideoCreativeType videoCreativeType, Long presetId) {
        switch (videoCreativeType) {
            case CPM_OUTDOOR:
            case CPM_INDOOR:
            case VIDEO_CONSTRUCTOR:
            case CPM_YNDX_FRONTPAGE:
                return getLimits(videoCreativeType, presetId).getAllowedVideoHwRatio();
            case CPM:
            case NON_SKIPPABLE_CPM:
            case PRICE_CAMPS_NON_SKIPPABLE_CPM:
            case PRICE_CAMPS_CPM:
            case MOBILE_CONTENT:
            case MOBILE_CONTENT_VIDEO:
            case CPC:
            case IN_BANNER:
            case TEXT:
                List<String> ratios = new ArrayList<>();
                ratios.add(null);
                ratios.addAll(getLimits(videoCreativeType, presetId).getAllowedVideoHwRatio());
                return ratios;
            default:
                throw new IllegalArgumentException("Unknown creative type: " + videoCreativeType);
        }
    }

    public VideoLimitsInterface getLimits(VideoCreativeType videoCreativeType, Set<String> features, @Nullable Long presetId) {
        final VideoLimits videoLimits;

        switch (videoCreativeType) {
            case CPM_OUTDOOR:
                videoLimits = outdoorLimits;
                break;
            case CPC:
                videoLimits = cpcLimits;
                break;
            case IN_BANNER:
            case CPM:
            case PRICE_CAMPS_CPM:
                videoLimits = cpmLimits;
                break;
            case MOBILE_CONTENT:
                videoLimits = mobileContentLimits;
                break;
            case MOBILE_CONTENT_VIDEO:
                videoLimits = mobileContentVideoLimits;
                break;
            case CPM_INDOOR:
                videoLimits = indoorLimits;
                break;
            case VIDEO_CONSTRUCTOR:
            case VIDEO_CONSTRUCTOR_FEED:
                videoLimits = videoConstructorLimits;
                break;
            case CPM_AUDIO:
                videoLimits = cpmAudioLimits;
                break;
            case CPM_YNDX_FRONTPAGE:
                videoLimits = cpmYndxFrontpageLimits;
                break;
            default:
                videoLimits = defaultLimits;
                break;
        }

        if (videoCreativeType == VideoCreativeType.CPM) {
            if (features.contains(LONG_VIDEO_FEATURE)) {
                return longCpm;
            }
        }

        if (videoCreativeType == VideoCreativeType.NON_SKIPPABLE_CPM || videoCreativeType == VideoCreativeType.PRICE_CAMPS_NON_SKIPPABLE_CPM) {
            if (features.contains(UNRESTRICTED_NON_SKIPPABLE_VIDEO_FEATURE)) {
                return cpmLimits;
                // Фича про 20 сек должна быть в приоритете
                // Чтобы при 2-х фичах у клиента срабатывали ограничения 20 секундного непропуска
            } else if (features.contains(SkipOffsetUtils.ENABLE_NON_SKIPPABLE_VIDEO_20_SECONDS)) {
                return nonSkippableCpm20Seconds;
            } else if (features.contains(SkipOffsetUtils.ENABLE_NON_SKIPPABLE_VIDEO_15_SECONDS)) {
                return nonSkippableCpm15Seconds;
            } else {
                return cpmLimits;
            }
        }

        if (videoCreativeType == VideoCreativeType.CPM_AUDIO && presetId != null) {
            if (presetId == 302) {
                return cpmAudio15SecLimits;
            } else if (presetId == 303) {
                return cpmAudio30SecLimits;
            } else if (presetId == 304) {
                return cpmAudio45SecLimits;
            } else {
                return cpmAudioLimits;
            }
        }

        return videoLimits;
    }

}
