package ru.yandex.canvas.service.video;

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

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;

import ru.yandex.canvas.model.stillage.StillageFileInfo;
import ru.yandex.canvas.model.video.AudioFiles;
import ru.yandex.canvas.model.video.files.FileStatus;
import ru.yandex.canvas.repository.video.AudioFilesRepository;
import ru.yandex.canvas.service.DirectService;
import ru.yandex.canvas.service.FileValidator;
import ru.yandex.canvas.service.VideoLimitsInterface;

public class AudioUploadService {
    private final AudioFilesRepository audioFilesRepository;
    private final VideoLimitsService videoLimitsService;
    private final DirectService directService;

    public AudioUploadService(AudioFilesRepository audioFilesRepository,
                              VideoLimitsService videoLimitsService,
                              DirectService directService) {
        this.audioFilesRepository = audioFilesRepository;
        this.videoLimitsService = videoLimitsService;
        this.directService = directService;
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class MetaDataInfo {
        private Double duration;
        private Long bitrate;
        private MetaDataInfoStream stream;
        private List<MetaDataInfoStream> videoStreams;
        private List<MetaDataInfoStream> audioStreams;
        private Set<String> flags;

        public Long getBitrate() {
            return bitrate;
        }

        public MetaDataInfo setBitrate(Long bitrate) {
            this.bitrate = bitrate;
            return this;
        }

        public Double getDuration() {
            return duration;
        }

        public MetaDataInfo setDuration(Double duration) {
            this.duration = duration;
            return this;
        }

        public Set<String> getFlags() {
            return flags;
        }
        public MetaDataInfo setFlags(Set<String> flags) {
            this.flags = flags;
            return this;
        }
        public List<MetaDataInfoStream> getVideoStreams() {
            return videoStreams;
        }
        public List<MetaDataInfoStream> getAudioStreams() {
            return audioStreams;
        }
        public void setVideoStreams(List<MetaDataInfoStream> videoStreams) {
            this.videoStreams = videoStreams;
        }
        public void setAudioStreams(List<MetaDataInfoStream> audioStreams) {
            this.audioStreams = audioStreams;
        }
        public MetaDataInfoStream getStream() {
            return stream;
        }

        public MetaDataInfo setStream(MetaDataInfoStream stream) {
            this.stream = stream;
            return this;
        }

        @JsonIgnoreProperties(ignoreUnknown = true)
        public static class MetaDataInfoStream {
            private MetaDataInfoStreamBaseInfo baseInfo;

            public MetaDataInfoStreamBaseInfo getBaseInfo() {
                return baseInfo;
            }

            public MetaDataInfoStream setBaseInfo(MetaDataInfoStreamBaseInfo baseInfo) {
                this.baseInfo = baseInfo;
                return this;
            }
        }

        @JsonIgnoreProperties(ignoreUnknown = true)
        public static class MetaDataInfoStreamBaseInfo {
            private String codec;
            private String channelLayout;
            private Long bitrate;
            private Long sampleRate;
            private Long channelCount;

            public String getCodec() {
                return codec;
            }

            public MetaDataInfoStreamBaseInfo setCodec(String codec) {
                this.codec = codec;
                return this;
            }

            public String getChannelLayout() {
                return channelLayout;
            }

            public MetaDataInfoStreamBaseInfo setChannelLayout(String channelLayout) {
                this.channelLayout = channelLayout;
                return this;
            }

            public Long getBitrate() {
                return bitrate;
            }

            public MetaDataInfoStreamBaseInfo setBitrate(Long bitrate) {
                this.bitrate = bitrate;
                return this;
            }

            public Long getSampleRate() {
                return sampleRate;
            }

            public MetaDataInfoStreamBaseInfo setSampleRate(Long sampleRate) {
                this.sampleRate = sampleRate;
                return this;
            }

            public Long getChannelCount() {
                return channelCount;
            }

            public MetaDataInfoStreamBaseInfo setChannelCount(Long channelCount) {
                this.channelCount = channelCount;
                return this;
            }
        }
    }

    public static MetaDataInfo parseMetaData(StillageFileInfo info) {
        return new ObjectMapper().convertValue(info.getMetadataInfo(), MetaDataInfo.class);
    }

    protected void beforeInsert(AudioFiles record, StillageFileInfo info) {
        if (info.getMetadataInfo().containsKey("duration")
                && info.getMetadataInfo().get("duration") instanceof Double) {
            record.setDuration((Double) info.getMetadataInfo().get("duration"));
        }
        record.setStatus(FileStatus.CONVERTING);
    }

    public AudioFiles upload(AudioFiles record, StillageFileInfo info, VideoCreativeType videoCreativeType,
                             Long presetId) {
        Set<String> features = directService.getFeatures(record.getClientId(), null);
        VideoLimitsInterface limits = videoLimitsService.getLimits(videoCreativeType, features, presetId);

        FileValidator validator = new AudioValidator(info, parseMetaData(info), limits);
        validator.validate();
        beforeInsert(record, info);

        return audioFilesRepository.save(record);
    }
}
