package rd.service.activity;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.yitter.idgen.YitIdHelper;
import rd.dao.mapper.activity.ActivityTargetMapper;
import rd.data.code.ServiceCode;
import rd.data.dto.activity.ActivityTargetAddDto;
import rd.data.dto.activity.ActivityTargetUpdateDto;
import rd.data.db.table.ActivityTarget;
import rd.exception.ServiceException;

import rd.service.cache.GlobalCache;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
public class ActivityTargetService {
    private final ActivityTargetMapper activityTargetMapper;

    public ActivityTargetService(ActivityTargetMapper activityTargetMapper) {
        this.activityTargetMapper = activityTargetMapper;
    }

    private static String getActivityTargetCourseCacheKey(Long majorId, Integer grade, Long activityId) {
        return String.format("%d:%d:%d", majorId, grade, activityId);
    }

    public List<Long> getMajorGradeActivityCandidateCourses(Long majorId, Integer grade, Long activityId) {
        var majorGradeActivityTarget = GlobalCache.ActivityTargetCourseCache.get(
                getActivityTargetCourseCacheKey(majorId, grade, activityId),
                key -> activityTargetMapper.selectOne(new LambdaQueryWrapper<ActivityTarget>()
                        .eq(ActivityTarget::getGrade, grade)
                        .eq(ActivityTarget::getMajor, majorId)
                        .eq(ActivityTarget::getActivity, activityId)
                        .eq(ActivityTarget::getDeleted, false)
                        .last("limit 1")
                )
        );

        if (majorGradeActivityTarget == null) {
            return new ArrayList<>();
        }

        return Arrays.asList(majorGradeActivityTarget.getCourseList());
    }

    public List<ActivityTarget> getActivityTargetList(Long activityId) {
        return activityTargetMapper.selectList(new LambdaQueryWrapper<ActivityTarget>()
                .eq(ActivityTarget::getActivity, activityId)
                .eq(ActivityTarget::getDeleted, false)
        );
    }

    public ActivityTarget getActivityTargetInfo(Long id) {
        return activityTargetMapper.selectOne(new LambdaQueryWrapper<ActivityTarget>()
                .eq(ActivityTarget::getId, id)
                .eq(ActivityTarget::getDeleted, false)
                .last("limit 1")
        );
    }

    public void addActivityTargetCourse(Long activityId, ActivityTargetAddDto activityTargetAddDto) {
        Integer grade = activityTargetAddDto.getGrade();
        Long majorId = activityTargetAddDto.getMajor();

        var exists = activityTargetMapper.exists(new LambdaQueryWrapper<ActivityTarget>()
                .eq(ActivityTarget::getGrade, grade)
                .eq(ActivityTarget::getMajor, majorId)
                .eq(ActivityTarget::getActivity, activityId)
                .eq(ActivityTarget::getDeleted, false)
        );
        if (exists) {
            throw ServiceException.error(
                    ServiceCode.DataDuplicate,
                    String.format("数据重复：年级='%s'，专业ID='%d'，活动ID='%d'", grade, majorId, activityId)
            );
        }

        Long id = YitIdHelper.nextId();
        ActivityTarget activityTarget = convert(activityTargetAddDto);
        activityTarget.setId(id);
        activityTarget.setActivity(activityId);

        activityTargetMapper.insert(activityTarget);

        GlobalCache.ActivityTargetCourseCache.put(
                getActivityTargetCourseCacheKey(majorId, grade, activityId),
                activityTarget
        );
    }

    private static ActivityTarget convert(ActivityTargetAddDto activityTargetAddDto) {
        ActivityTarget activityTarget = new ActivityTarget();
        activityTarget.setGrade(activityTargetAddDto.getGrade());
        activityTarget.setMajor(activityTargetAddDto.getMajor());
        activityTarget.setCourseList(activityTargetAddDto.getCourse().toArray(new Long[0]));
        activityTarget.setCreateTime(LocalDateTime.now());
        activityTarget.setEditTime(LocalDateTime.now());
        activityTarget.setDeleted(false);

        return activityTarget;
    }

    public void duplicateFromExistsActivity(Long srcAct, Long dstAct) {
        var exists = activityTargetMapper.exists(new LambdaQueryWrapper<ActivityTarget>()
                .eq(ActivityTarget::getActivity, dstAct)
                .eq(ActivityTarget::getDeleted, false)
        );
        if (exists) {
            throw ServiceException.error(
                    ServiceCode.DataDuplicate,
                    "要从其他活动复制对象信息，请先保证目标活动的活动对象数据是空的。"
            );
        }

        var activityTargetList = this.getActivityTargetList(srcAct);
        if (activityTargetList == null || activityTargetList.isEmpty()) {
            throw ServiceException.error(ServiceCode.DataNotExists, "源活动没有设置活动对象数据");
        }

        for (ActivityTarget activityTarget : activityTargetList) {
            Long id = YitIdHelper.nextId();
            activityTarget.setId(id);
            activityTarget.setActivity(dstAct);
            activityTarget.setCreateTime(LocalDateTime.now());
            activityTarget.setEditTime(LocalDateTime.now());
        }

        activityTargetMapper.insertBatchSomeColumn(activityTargetList);

        for (ActivityTarget activityTarget : activityTargetList) {
            GlobalCache.ActivityTargetCourseCache.put(
                    getActivityTargetCourseCacheKey(activityTarget.getMajor(), activityTarget.getGrade(), dstAct),
                    activityTarget
            );
        }
    }

    public void removeActivityTargetCourse(Long id) {
        var activityTarget = activityTargetMapper.selectOne(new LambdaQueryWrapper<ActivityTarget>()
                .eq(ActivityTarget::getId, id)
                .eq(ActivityTarget::getDeleted, false)
                .last("limit 1")
        );

        if (activityTarget == null) {
            return;
        }

        activityTargetMapper.update(null, new LambdaUpdateWrapper<ActivityTarget>()
                .set(ActivityTarget::getDeleted, true)
                .eq(ActivityTarget::getId, id)
                .eq(ActivityTarget::getDeleted, false)
        );

        GlobalCache.ActivityTargetCourseCache.invalidate(
                getActivityTargetCourseCacheKey(
                        activityTarget.getMajor(), activityTarget.getGrade(), activityTarget.getActivity()
                )
        );
    }

    public void updateActivityTargetCourse(Long id, ActivityTargetUpdateDto activityTargetUpdateDto) {
        ActivityTarget activityTarget = activityTargetMapper.selectOne(new LambdaQueryWrapper<ActivityTarget>()
                .eq(ActivityTarget::getId, id)
                .eq(ActivityTarget::getDeleted, false)
                .last("limit 1")
        );

        if (activityTarget == null) {
            return;
        }

        var legacyActId = activityTarget.getActivity();
        var legacyMajor = activityTarget.getMajor();
        var legacyGrade = activityTarget.getGrade();

        activityTarget.setGrade(activityTargetUpdateDto.getGrade());
        activityTarget.setMajor(activityTargetUpdateDto.getMajor());
        activityTarget.setCourseList(activityTargetUpdateDto.getCourse().toArray(new Long[0]));

        activityTargetMapper.update(activityTarget, new LambdaUpdateWrapper<ActivityTarget>()
                .eq(ActivityTarget::getId, id)
                .eq(ActivityTarget::getDeleted, false)
        );

        GlobalCache.ActivityTargetCourseCache.invalidate(getActivityTargetCourseCacheKey(legacyMajor, legacyGrade, legacyActId));
        GlobalCache.ActivityTargetCourseCache.put(
                getActivityTargetCourseCacheKey(
                        activityTarget.getMajor(), activityTarget.getGrade(), activityTarget.getActivity()
                ), activityTarget
        );
    }
}
