package cn.novalon.gym.manage.groupcourse.service.impl;

import cn.novalon.gym.manage.common.util.RedisUtil;
import cn.novalon.gym.manage.groupcourse.domain.CourseLabel;
import cn.novalon.gym.manage.groupcourse.domain.GroupCourse;
import cn.novalon.gym.manage.groupcourse.repository.ICourseLabelRepository;
import cn.novalon.gym.manage.groupcourse.repository.IGroupCourseRepository;
import cn.novalon.gym.manage.groupcourse.service.ICourseLabelService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;

@Service
public class CourseLabelService implements ICourseLabelService {

    private static final Logger logger = LoggerFactory.getLogger(CourseLabelService.class);
    private static final String CACHE_KEY_DETAIL_PREFIX = "group_course:detail:";

    private final ICourseLabelRepository courseLabelRepository;
    private final IGroupCourseRepository groupCourseRepository;
    private final RedisUtil redisUtil;

    public CourseLabelService(ICourseLabelRepository courseLabelRepository,
                              IGroupCourseRepository groupCourseRepository,
                              RedisUtil redisUtil) {
        this.courseLabelRepository = courseLabelRepository;
        this.groupCourseRepository = groupCourseRepository;
        this.redisUtil = redisUtil;
    }

    private Mono<Void> invalidateGroupCourseDetailCache(Long typeId) {
        return groupCourseRepository.findByCourseType(typeId)
                .flatMap(course -> {
                    String cacheKey = CACHE_KEY_DETAIL_PREFIX + course.getId();
                    return redisUtil.delete(cacheKey)
                            .doOnSuccess(deleted -> logger.debug("清除团课详情缓存 - courseId={}", course.getId()));
                })
                .then();
    }

    @Override
    public Mono<CourseLabel> findById(Long id) {
        return courseLabelRepository.findById(id);
    }

    @Override
    public Flux<CourseLabel> findAll() {
        return courseLabelRepository.findAll();
    }

    @Override
    public Flux<CourseLabel> findByKeyword(String keyword) {
        return courseLabelRepository.findByKeyword(keyword);
    }

    @Override
    public Mono<CourseLabel> create(CourseLabel courseLabel) {
        return courseLabelRepository.findByLabelName(courseLabel.getLabelName())
                .flatMap(existing -> Mono.<CourseLabel>error(new RuntimeException("标签名称已存在")))
                .switchIfEmpty(courseLabelRepository.save(courseLabel))
                .doOnSuccess(label -> logger.info("标签创建成功 - id={}, name={}", label.getId(), label.getLabelName()))
                .doOnError(error -> logger.error("标签创建失败 - error: {}", error.getMessage()));
    }

    @Override
    public Mono<CourseLabel> update(Long id, CourseLabel courseLabel) {
        courseLabel.setId(id);
        return courseLabelRepository.update(courseLabel)
                .doOnSuccess(label -> logger.info("标签更新成功 - id={}", id))
                .doOnError(error -> logger.error("标签更新失败 - id={}, error: {}", id, error.getMessage()));
    }

    @Override
    public Mono<Void> delete(Long id) {
        return courseLabelRepository.deleteById(id)
                .doOnSuccess(v -> logger.info("标签删除成功 - id={}", id))
                .doOnError(error -> logger.error("标签删除失败 - id={}, error: {}", id, error.getMessage()));
    }

    @Override
    public Flux<CourseLabel> findByTypeId(Long typeId) {
        return courseLabelRepository.findByTypeId(typeId);
    }

    @Override
    public Mono<Void> addLabelsToType(Long typeId, List<Long> labelIds) {
        return courseLabelRepository.addLabelsToType(typeId, labelIds)
                .then(invalidateGroupCourseDetailCache(typeId))
                .doOnSuccess(v -> logger.info("标签添加到类型成功 - typeId={}, labelIds={}", typeId, labelIds))
                .doOnError(error -> logger.error("标签添加到类型失败 - typeId={}, error: {}", typeId, error.getMessage()));
    }

    @Override
    public Mono<Void> removeLabelFromType(Long typeId, Long labelId) {
        return courseLabelRepository.removeLabelFromType(typeId, labelId)
                .then(invalidateGroupCourseDetailCache(typeId))
                .doOnSuccess(v -> logger.info("从类型移除标签成功 - typeId={}, labelId={}", typeId, labelId))
                .doOnError(error -> logger.error("从类型移除标签失败 - typeId={}, labelId={}, error: {}", typeId, labelId, error.getMessage()));
    }

    @Override
    public Mono<Void> clearLabelsFromType(Long typeId) {
        return courseLabelRepository.clearLabelsFromType(typeId)
                .then(invalidateGroupCourseDetailCache(typeId))
                .doOnSuccess(v -> logger.info("清空类型标签成功 - typeId={}", typeId))
                .doOnError(error -> logger.error("清空类型标签失败 - typeId={}, error: {}", typeId, error.getMessage()));
    }
}