package com.izouma.wenlvju.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.izouma.wenlvju.domain.*;
import com.izouma.wenlvju.domain.performance.Performance;
import com.izouma.wenlvju.dto.PageQuery;
import com.izouma.wenlvju.enums.ApplyStatus;
import com.izouma.wenlvju.enums.AuthorityName;
import com.izouma.wenlvju.exception.BusinessException;
import com.izouma.wenlvju.repo.*;
import com.izouma.wenlvju.repo.performance.PerformanceRepo;
import com.izouma.wenlvju.security.Authority;
import com.izouma.wenlvju.security.JwtTokenUtil;
import com.izouma.wenlvju.security.JwtUserFactory;
import com.izouma.wenlvju.utils.JpaUtils;
import com.izouma.wenlvju.utils.ObjUtils;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class PerformanceApplyService {

    private final PerformanceApplyRepo performanceApplyRepo;
    private final PerformanceRepo      performanceRepo;
    private final ArtTypeRepo          artTypeRepo;
    private final OrganizationRepo     organizationRepo;
    private final PersonRepo           personRepo;
    private final UserRepo             userRepo;
    private final JwtTokenUtil         jwtTokenUtil;
    private final PerformanceScoreRepo performanceScoreRepo;

    public Page<PerformanceApply> all(PageQuery pageQuery) {
        Page<PerformanceApply> all = performanceApplyRepo.findAll(JpaUtils.toSpecification(pageQuery, PerformanceApply.class), JpaUtils
                .toPageRequest(pageQuery));
        Set<Long> artTypeId = new HashSet<>();
        Set<Long> organizationId = new HashSet<>();
        all.forEach(apply -> {
            artTypeId.add(apply.getArtTypeId());
            organizationId.add(apply.getOrganizationId());
        });

        Map<Long, String> artMap = artTypeRepo.findAllById(artTypeId)
                .stream()
                .collect(Collectors.toMap(ArtType::getId, ArtType::getName));
        Map<Long, String> organzationMap = organizationRepo.findAllById(organizationId)
                .stream()
                .collect(Collectors.toMap(Organization::getId, Organization::getName));

        return all.map(apply -> {
            apply.setArtType(artMap.get(apply.getArtTypeId()));
            apply.setOrganizer(organzationMap.get(apply.getOrganizationId()));
            return apply;
        });

    }

    public void audit(Long id, Boolean pass) {
        PerformanceApply apply = performanceApplyRepo.findById(id).orElseThrow(new BusinessException("无此展演申请"));
        if (pass) {
            apply.setStatus(ApplyStatus.PASS);
        } else {
            apply.setStatus(ApplyStatus.DENY);
        }
        performanceApplyRepo.save(apply);
    }

    public List<PerformanceApply> autoArrangement1(Long performanceId) {
        Performance performance = performanceRepo.findById(performanceId).orElseThrow(new BusinessException("无记录"));
        if (LocalDate.now().isBefore(performance.getEndDate())) {
            throw new BusinessException("报名结束后才可以自动编排");
        }

        // 只编排通过的
        List<PerformanceApply> applyList =
                performanceApplyRepo.findAllByStatusAndPerformanceId(ApplyStatus.PASS, performanceId);
//        LocalDate startDate = performance.getEventStartDate();
//        LocalDate endDate = performance.getEndDate();
//        LocalTime dayStart = performance.getMorningStartTime();
//        LocalTime dayEnd = performance.getMorningEndTime();
//        Long length = performance.getProgrammeLength();

//        LocalTime dayChange = dayStart;
//        for (PerformanceApply apply : applyList) {
//            if (start.isAfter(endDate)) {
//                throw new BusinessException("展示时间过短，请编辑展演结束时间。");
//            }
//            if (dayChange.isAfter(dayEnd)) {
//                dayChange = performance.getAfternoonStartTime();
//            }
//            apply.setShowStartTime(LocalDateTime.of(startDate, dayChange));
//            dayChange = dayChange.plusMinutes(30);
//            apply.setShowEndTime(LocalDateTime.of(startDate, dayChange));
//        }


        Set<Long> artTypeId = new HashSet<>();
        Set<Long> organizationId = new HashSet<>();
        applyList.forEach(apply -> {
            artTypeId.add(apply.getArtTypeId());
            organizationId.add(apply.getOrganizationId());
        });

        Map<Long, String> artMap = artTypeRepo.findAllById(artTypeId)
                .stream()
                .collect(Collectors.toMap(ArtType::getId, ArtType::getName));
        Map<Long, String> organzationMap = organizationRepo.findAllById(organizationId)
                .stream()
                .collect(Collectors.toMap(Organization::getId, Organization::getName));
        applyList.forEach(apply -> {
            apply.setArtType(artMap.get(apply.getArtTypeId()));
            apply.setOrganizer(organzationMap.get(apply.getOrganizationId()));
        });
        return applyList;
    }


    public void saveArrangement(String applies) {
        if (StrUtil.isEmpty(applies)) {
            return;
        }
        List<PerformanceApply> applyList = JSONObject.parseArray(applies, PerformanceApply.class);
        List<Long> ids = applyList.stream().map(PerformanceApply::getId).collect(Collectors.toList());
        Map<Long, PerformanceApply> applyMap = performanceApplyRepo.findAllById(ids)
                .stream()
                .collect(Collectors.toMap(PerformanceApply::getId, apply -> apply));

        applyList.forEach(list -> {
            PerformanceApply apply = applyMap.get(list.getId());
            if (ObjectUtil.isNotNull(apply)) {
                ObjUtils.merge(apply, list);
                performanceApplyRepo.save(apply);
            }
        });
    }

    /*
    自动评奖
     */
    public void autoAwards(Long performanceId) {
//        List<PerformanceApply> applies = performanceApplyRepo.findAllByShowTimeIsNotNullAndPerformanceId(performanceId);
//        if (CollUtil.isEmpty(applies)) {
//            return;
//        }
//        applies.forEach(apply -> {
//            apply.setAwards("一等奖");
//            apply.setScore(100);
//            performanceApplyRepo.save(apply);
//        });
    }

    /**
     * 签到
     * 由管理人员先登陆，进行签到
     */
    public PerformanceApply signIn(Long id, Long userId) {
        PerformanceApply performanceApply = performanceApplyRepo.findById(id)
                .orElseThrow(new BusinessException("无此表演"));

        if (ObjectUtil.isNotNull(performanceApply.getSignInAt()) && ObjectUtil.isNotNull(performanceApply.getSignInBy())) {
            throw new BusinessException("已签到");
        }

        performanceApply.setSignInAt(LocalDateTime.now());
        performanceApply.setSignInBy(userId);

        return performanceApplyRepo.save(performanceApply);
    }

    /**
     * 扫描作品二维码，通过手机号获取身份
     */
    public Map<String, String> getAuth(Long id, String phone, String pPhone) {

        Map<String, String> map = new HashMap<>();

        if (phone.equals(pPhone)) {
            map.put("phone", phone);
            return map;
        }

        List<String> phones = personRepo.findAllByPerformanceApplyId(id)
                .stream()
                .map(Person::getPhone)
                .collect(Collectors.toList());
        if (phones.contains(phone)) {
            map.put("phone", phone);
            return map;
        }

        User user = userRepo.findByPhoneAndDelFalse(phone);
        if (ObjectUtil.isNull(user)) {
            throw new BusinessException("手机号错误");
        }
        if (!user.getAuthorities().contains(Authority.get(AuthorityName.ROLE_ADMIN))) {
            throw new BusinessException("无权限");
        }
        String token = jwtTokenUtil.generateToken(JwtUserFactory.create(user));
        map.put("phone", phone);
        map.put("token", token);
        return map;
    }

    /**
     * 评分
     */
    public void score(Long id, double score, Long userId) {
        PerformanceApply apply = performanceApplyRepo.findById(id).orElseThrow(new BusinessException("无此表演"));
        if (!ApplyStatus.PASS.equals(apply.getStatus())) {
            throw new BusinessException("此节目未通过审核");
        }
        if (ObjectUtil.isNull(apply.getShowStartTime())) {
            throw new BusinessException("无表演时间");
        }
        if (LocalDateTime.now().isBefore(apply.getShowStartTime())) {
            throw new BusinessException("节目暂未开始");
        }
        PerformanceScore score1 = performanceScoreRepo.findByPerformanceApplyIdAndUserId(id, userId);
        if (ObjectUtil.isNotNull(score1)) {
            throw new BusinessException("已打分");
        }

        PerformanceScore performanceScore = PerformanceScore.builder()
                .performanceApplyId(id)
                .score(score)
                .userId(userId)
                .build();
        performanceScoreRepo.save(performanceScore);

        double scores = performanceScoreRepo.findAllByPerformanceApplyId(id)
                .stream()
                .mapToDouble(PerformanceScore::getScore)
                .average()
                .orElse(0.0);

        double scores1 = (double) Math.round(scores * 10) / 10;
        apply.setScore(scores1);
        performanceApplyRepo.save(apply);
    }

    /**
     * 获取相关
     */
    public List<PerformanceApply> related(Long id) {
        PerformanceApply apply = performanceApplyRepo.findById(id).orElseThrow(new BusinessException("无记录"));
        List<PerformanceApply> applies = performanceApplyRepo.findAllByStatusAndPerformanceId(ApplyStatus.PASS, apply
                .getPerformanceId());
        return applies.stream()
                .filter(app -> app.getShowStartTime().isAfter(apply.getShowStartTime()))
                .sorted(Comparator.comparing(PerformanceApply::getShowStartTime))
                .collect(Collectors.toList());
    }
}
