package com.sonymusic.dx.dxuiservice.service;

import com.sonymusic.dx.dxuiservice.dto.*;
import com.sonymusic.dx.dxuiservice.model.TrackModel;
import com.sonymusic.dx.dxuiservice.util.DxUIUtil;
import com.sonymusic.dx.persistence.gras.*;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatusCode;
import org.springframework.stereotype.Service;
import org.springframework.web.ErrorResponseException;


import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class TrackService {

    @PersistenceContext(name = "dx-gras-persistence")
    private EntityManager em;

    private final Logger log = LoggerFactory.getLogger(getClass());

    public TrackModel getTrackByTrackNo(String trackNo,String trackExt) {

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<TrackDTO> cq1 = cb.createQuery(TrackDTO.class);
        Root<Track> root = cq1.from(Track.class);
        Join<Track,TrackPk> trackTrackPkJoin = root.join("trackPk",JoinType.LEFT);
        List<Predicate> predicates = new ArrayList<>();
        if (trackExt==null){
            trackExt="  ";
        }
        predicates.add(cb.equal(trackTrackPkJoin.get("trackNo"),trackNo));
        predicates.add(cb.equal(trackTrackPkJoin.get("trackExt"),trackExt));
        cb.and(predicates.toArray(new Predicate[0]));
        return getTrackModel(root,cq1,cb,predicates);

    }

    public TrackModel getTrackByIsrc(String isrcNo) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<TrackDTO> cq1 = cb.createQuery(TrackDTO.class);
        Root<Track> root = cq1.from(Track.class);
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(cb.equal(root.get("isrc"),isrcNo));
        cb.and(predicates.toArray(new Predicate[0]));
        return getTrackModel(root,cq1,cb,predicates);
    }


    public TrackModel getTrackModel(Root<Track> root, CriteriaQuery<TrackDTO> cq1, CriteriaBuilder cb, List<Predicate> predicates){
        Join<Track, Song> trackSongJoin = root.join("song", JoinType.LEFT);
        Join<Track, Language> trackLanguageJoin = root.join("language",JoinType.LEFT);
        Join<Track, LyricsType> trackLyricsTypeJoin = root.join("lyricsType",JoinType.LEFT);
        Join<Track, Company> trackCompanyJoin = root.join("repertoireOwner",JoinType.LEFT);
        Join<Track,TrackType> trackTrackTypeJoin =root.join("trackType",JoinType.LEFT);
        Join<Track,Genre> trackGenreJoin = root.join("genre",JoinType.LEFT);
        Join<Track,TrackSubType> trackSubTypeJoin=root.join("trackSubType",JoinType.LEFT);
        Join<Track,TrackParticipant> trackTrackParticipantJoin=root.join("trackParticipants",JoinType.LEFT);
        Join<Song, Language> songLanguageJoin = trackSongJoin.join("language",JoinType.LEFT);
        Join<Track,DataSource> trackDataSourceJoin = root.join("dataSource",JoinType.LEFT);
        Join<Song,SongCountry> songSongCountryJoin = trackSongJoin.join("songCountries",JoinType.LEFT);
        Join<Track,TrackPk> trackTrackPkJoin = root.join("trackPk",JoinType.LEFT);
        Join<Track, TrackMediaType>  trackMediaTypeJoin = root.join("trackMediaType", JoinType.LEFT);
        Join<Track, SoundCode> trackSoundCodeJoin = root.join("soundCode", JoinType.LEFT);
        Join<Track, Country> trackCountryJoin = root.join("recordedInCountry",JoinType.LEFT);
        Join<Track,AudioEncodingType> trackAudioEncodingTypeJoin = root.join("sourceAudioEncodingType",JoinType.LEFT);
        Join<Track,VideoEncodingType> trackVideoEncodingTypeJoin = root.join("sourceVideoEncodingType",JoinType.LEFT);

        cq1.select(cb.construct(TrackDTO.class,
                root.get("isrc")
                ,root.get("isComplete")
                ,root.get("takenFromIsrc")
                ,root.get("trackMatchNameSupplemental")
                ,root.get("completeUser")
                ,root.get("gridNo")
                ,root.get("pLine")
                ,root.get("cLine")
                ,root.get("matrixNo")
                ,root.get("playTime")
                ,root.get("dateRecorded")
                ,root.get("recordingPeriod")
                ,root.get("placeRecorded")
                ,root.get("originalReleaseDate")
                ,root.get("isLiveRecording")
                ,root.get("relatedAudioIsrc")
                ,cb.construct(SongLanguageDTO.class
                        ,songLanguageJoin.get("languageKey")
                        ,songLanguageJoin.get("languageName")),
                cb.construct(LanguageDTO.class
                        ,trackLanguageJoin.get("languageKey")
                        ,trackLanguageJoin.get("languageName")),
                cb.construct(TrackLyricsDTO.class
                        ,trackLyricsTypeJoin.get("lyricsTypeKey")
                        ,trackLyricsTypeJoin.get("lyricsTypeName")),
                cb.construct(TrackRepertoireOwnerDTO.class
                        ,trackCompanyJoin.get("companyKey")
                        ,trackCompanyJoin.get("companyName")),
                cb.construct(TrackTypeDTO.class
                        ,trackTrackTypeJoin.get("trackTypeName")
                        ,trackTrackTypeJoin.get("trackTypeKey")),
                cb.construct(MaintenanceOwnerDTO.class
                        ,trackCompanyJoin.get("companyKey")
                        ,trackCompanyJoin.get("companyName")),
                cb.construct(GenreDTO.class,
                        trackGenreJoin.get("genreKey"),
                        trackGenreJoin.get("genreName")),
                cb.construct(TrackSubTypeDTO.class,
                        trackSubTypeJoin.get("trackSubTypeKey"),
                        trackSubTypeJoin.get("trackSubTypeName")),
                cb.construct(DataSourceDTO.class,
                		trackDataSourceJoin.get("dataSourceId"),
                        trackDataSourceJoin.get("dataSourceName")),
                cb.construct(SongDTO.class,
                        trackSongJoin.get("songNumber"),
                        trackSongJoin.get("trackName")),
                cb.construct(TrackMediumDTO.class,
                        trackMediaTypeJoin.get("mediaTypeKey"),
                        trackMediaTypeJoin.get("mediaTypeName")),
                cb.construct(ContentDTO.class,
                        trackSoundCodeJoin.get("soundCodeKey"),
                        trackSoundCodeJoin.get("soundCodeName")),
                cb.construct(CountryDTO.class,
                        trackCountryJoin.get("countryName"),
                        trackCountryJoin.get("countryKey")),
                cb.construct(AudioEncodingTypeDTO.class,
                        trackAudioEncodingTypeJoin.get("audioEncodingKey"),
                        trackAudioEncodingTypeJoin.get("audioEncodingName")),
                cb.construct(VideoEncodingTypeDTO.class,
                        trackVideoEncodingTypeJoin.get("videoEncodingKey"),
                        trackVideoEncodingTypeJoin.get("videoEncodingName")),
        cb.construct(TrackPkDTO.class,
                trackTrackPkJoin.get("trackNo"),
                trackTrackPkJoin.get("trackExt"))));

        cq1.where(predicates.toArray(new Predicate[0]));
        cq1.distinct(true);
        List<TrackDTO> trackDTOS= em.createQuery(cq1).getResultList();
        if (trackDTOS.isEmpty()){
            throw new ErrorResponseException(HttpStatusCode.valueOf(400));
        }
        CriteriaQuery<TrackParticipantDTO> trackParticipanyCQ = cb.createQuery(TrackParticipantDTO.class);
        Root<Track> pRoot = trackParticipanyCQ.from(Track.class);
        Join<Track,TrackParticipant> trackParticipantJoin=pRoot.join("trackParticipants",JoinType.LEFT);
        trackParticipanyCQ.select(cb.construct(TrackParticipantDTO.class,
                        trackParticipantJoin.get("isMainArtist"),
                        trackParticipantJoin.get("participant")))
                .where(cb.equal(pRoot.get("trackPk").get("trackNo"),trackDTOS.get(0).getTrackPk().getTrackNo()),
                        cb.equal(trackParticipantJoin.get("isMainArtist"),true));

        List<TrackParticipantDTO> results = em.createQuery(trackParticipanyCQ).getResultList();
        String MainArtists = results.stream()
                .map(dto->dto.getParticipant().getFullName())
                .filter(Objects::nonNull)
                .collect(Collectors.joining(DxUIUtil.DX_DELIMITER));
        TrackDTO trackDTO = trackDTOS.get(0);
        TrackModel trackResponseModel = null;
        trackResponseModel = new TrackModel();
        trackResponseModel.setTrackTitle(trackDTO.getSong().getTrackName());
        trackResponseModel.setIsrcNo(trackDTO.getIscrNo());
        trackResponseModel.setTrackTitleSupplimental(trackDTO.getTrackMatchNameSupplemental());
        //ownership
        trackResponseModel.setpLine(trackDTO.getpLine());
        trackResponseModel.setTrackType(trackDTO.getTrackType().getTrackTypeName());
        trackResponseModel.setSubType(trackDTO.getTrackSubType().getTrackSubTypeName());
        //original source
        //has split deal
        if (trackDTO.getRecordingDate()!=null){
            String input = trackDTO.getRecordingDate();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            LocalDate localDate = LocalDate.parse(input, formatter);
            Date recordingDate = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
            trackResponseModel.setRecordingDate(recordingDate);
        }

        trackResponseModel.setRecordingPeriod(trackDTO.getRecordingPeriod());
        trackResponseModel.setRecordingLocation(trackDTO.getPlaceRecorded());
        trackResponseModel.setRecordingCountry(trackDTO.getCountry().getCountryName());
        trackResponseModel.setOriginalReleaseDate(trackDTO.getOriginalReleaseDate());
        if (trackDTO.getPlayTime()!=null){
            long hrs = trackDTO.getPlayTime() /3600;
            long mins = (trackDTO.getPlayTime() % 3600) / 60;
            long secs = trackDTO.getPlayTime() % 3600;
            trackResponseModel.setPlayTime(String.format("%02d:%02d:%02d", hrs, mins, secs));
        }
        trackResponseModel.setMainArtist(MainArtists);
        trackResponseModel.setMediaType(trackDTO.getTrackMedium().getMediaTypeName());
        trackResponseModel.setContent(trackDTO.getContent().getSoundCodeName());
        //is excerpt
        trackResponseModel.setRelAudioIsrc(trackDTO.getRelatedAudioIsrc());
        trackResponseModel.setcLine(trackDTO.getcLine());
        trackResponseModel.setAudioEncoding(trackDTO.getAudioEncoding().getAudioEncodingName());
        trackResponseModel.setLyricsIndicator(trackDTO.getLyricsIndicator().getLyricsTypeName());
        trackResponseModel.setLanguage(trackDTO.getLanguage().getLanguageName());
        trackResponseModel.setLiveRecording(trackDTO.isLiveRecording());
        trackResponseModel.setMatrixNo(trackDTO.getMatrixNo());
        trackResponseModel.setGrId(trackDTO.getGridNo());
        trackResponseModel.setTakenFromIsrc(trackDTO.getTakenFromIsrc());
        trackResponseModel.setGenre(trackDTO.getGenre().getGenreName());
        trackResponseModel.setRepertoireOwner(trackDTO.getRepertoireOwner().getCompanyName());
        //BU
        //song c line
        trackResponseModel.setVideoEncoding(trackDTO.getVideoEncoding().getVideoEncodingName());
        //prod credits
        trackResponseModel.setTitleLanguage(trackDTO.getTitleLanguage().getLanguageName());
        //footage type nm
        //excl.fr split dl.
        //rel isrc ver
        trackResponseModel.setCopyOwnerCountryName(trackDTO.getCountry().getCountryName());
        //asset suppl title internal
        trackResponseModel.setTrackNo(trackDTO.getTrackPk().getTrackNo());
        trackResponseModel.setTrackExt(trackDTO.getTrackPk().getTrackExt());
        return trackResponseModel;
    }

}
