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

import cn.hutool.core.bean.BeanUtil;
import cn.novalon.gym.manage.groupcourse.dao.GroupCourseRecommendDao;
import cn.novalon.gym.manage.groupcourse.domain.GroupCourseRecommend;
import cn.novalon.gym.manage.groupcourse.entity.GroupCourseRecommendEntity;
import cn.novalon.gym.manage.groupcourse.repository.IGroupCourseRecommendRepository;
import org.springframework.data.domain.Sort;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;

@Repository
public class GroupCourseRecommendRepository implements IGroupCourseRecommendRepository {

    private final GroupCourseRecommendDao recommendDao;
    private final R2dbcEntityTemplate r2dbcEntityTemplate;

    public GroupCourseRecommendRepository(GroupCourseRecommendDao recommendDao, 
                                          R2dbcEntityTemplate r2dbcEntityTemplate) {
        this.recommendDao = recommendDao;
        this.r2dbcEntityTemplate = r2dbcEntityTemplate;
    }

    @Override
    public Mono<GroupCourseRecommend> findById(Long id) {
        return recommendDao.findByIdAndDeletedAtIsNull(id)
                .map(this::toDomain);
    }

    @Override
    public Flux<GroupCourseRecommend> findAll() {
        return recommendDao.findAllByDeletedAtIsNull()
                .map(this::toDomain);
    }

    @Override
    public Flux<GroupCourseRecommend> findAll(String sortBy, String sortOrder) {
        Sort.Direction direction = "asc".equalsIgnoreCase(sortOrder) 
                ? Sort.Direction.ASC 
                : Sort.Direction.DESC;
        Sort sort = Sort.by(direction, sortBy);
        return recommendDao.findAllByDeletedAtIsNull(sort)
                .map(this::toDomain);
    }

    @Override
    public Flux<GroupCourseRecommend> findAllActive() {
        return recommendDao.findByIsActiveTrueAndDeletedAtIsNull(Sort.by(Sort.Direction.DESC, "priority"))
                .map(this::toDomain);
    }

    @Override
    public Flux<GroupCourseRecommend> findByCourseId(Long courseId) {
        return recommendDao.findByCourseIdAndDeletedAtIsNull(courseId)
                .map(this::toDomain);
    }

    @Override
    public Mono<GroupCourseRecommend> findActiveByCourseId(Long courseId) {
        return recommendDao.findByCourseIdAndDeletedAtIsNullAndIsActiveTrue(courseId)
                .map(this::toDomain);
    }

    @Override
    public Mono<GroupCourseRecommend> save(GroupCourseRecommend recommend) {
        GroupCourseRecommendEntity entity = toEntity(recommend);
        entity.setCreatedAt(LocalDateTime.now());
        entity.setUpdatedAt(LocalDateTime.now());
        if (entity.getPriority() == null) {
            entity.setPriority(0);
        }
        if (entity.getIsActive() == null) {
            entity.setIsActive(true);
        }

        return recommendDao.save(entity)
                .map(this::toDomain);
    }

    @Override
    public Mono<GroupCourseRecommend> update(GroupCourseRecommend recommend) {
        GroupCourseRecommendEntity entity = toEntity(recommend);
        entity.setUpdatedAt(LocalDateTime.now());

        return r2dbcEntityTemplate.update(entity)
                .then(findById(recommend.getId()));
    }

    @Override
    public Mono<Void> deleteById(Long id) {
        return recommendDao.softDelete(id, LocalDateTime.now())
                .then();
    }

    @Override
    public Mono<Void> deleteByCourseId(Long courseId) {
        return recommendDao.softDeleteByCourseId(courseId, LocalDateTime.now())
                .then();
    }

    @Override
    public Mono<GroupCourseRecommend> updateActiveStatus(Long id, Boolean isActive) {
        return recommendDao.updateActiveStatus(id, isActive, LocalDateTime.now())
                .flatMap(updated -> {
                    if (updated > 0) {
                        return findById(id);
                    }
                    return Mono.empty();
                });
    }

    private GroupCourseRecommend toDomain(GroupCourseRecommendEntity entity) {
        if (entity == null) {
            return null;
        }
        GroupCourseRecommend recommend = new GroupCourseRecommend();
        BeanUtil.copyProperties(entity, recommend);
        return recommend;
    }

    private GroupCourseRecommendEntity toEntity(GroupCourseRecommend domain) {
        if (domain == null) {
            return null;
        }
        GroupCourseRecommendEntity entity = new GroupCourseRecommendEntity();
        BeanUtil.copyProperties(domain, entity);
        if (domain.getId() != null) {
            entity.markNotNew();
        }
        return entity;
    }
}