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

import cn.novalon.gym.manage.groupcourse.converter.GroupCourseConverter;
import cn.novalon.gym.manage.groupcourse.dao.GroupCourseBookingDao;
import cn.novalon.gym.manage.groupcourse.domain.GroupCourseBooking;
import cn.novalon.gym.manage.groupcourse.entity.GroupCourseBookingEntity;
import cn.novalon.gym.manage.groupcourse.repository.IGroupCourseBookingRepository;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * 团课预约记录Repository实现类
 * 
 * @author 张翔
 * @date 2026-06-01
 */
@Repository
public class GroupCourseBookingRepository implements IGroupCourseBookingRepository {

    private final GroupCourseBookingDao groupCourseBookingDao;
    private final GroupCourseConverter groupCourseConverter;

    public GroupCourseBookingRepository(GroupCourseBookingDao groupCourseBookingDao,
                                        GroupCourseConverter groupCourseConverter) {
        this.groupCourseBookingDao = groupCourseBookingDao;
        this.groupCourseConverter = groupCourseConverter;
    }

    @Override
    public Mono<GroupCourseBooking> findById(Long id) {
        return groupCourseBookingDao.findByIdIsAndDeletedAtIsNull(id)
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Flux<GroupCourseBooking> findByMemberId(Long memberId) {
        return groupCourseBookingDao.findByMemberIdAndDeletedAtIsNull(memberId, Sort.by(Sort.Direction.DESC, "bookingTime"))
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Flux<GroupCourseBooking> findByCourseId(Long courseId) {
        return groupCourseBookingDao.findByCourseIdAndDeletedAtIsNull(courseId)
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Mono<GroupCourseBooking> findByCourseIdAndMemberId(Long courseId, Long memberId) {
        return groupCourseBookingDao.findByCourseIdAndMemberIdAndDeletedAtIsNull(courseId, memberId)
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Mono<GroupCourseBooking> findValidBooking(Long courseId, Long memberId) {
        return groupCourseBookingDao.findByCourseIdAndMemberIdAndStatusAndDeletedAtIsNull(courseId, memberId, "0")
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Mono<Long> countValidBookings(Long courseId) {
        return groupCourseBookingDao.countByCourseIdAndStatusAndDeletedAtIsNull(courseId, "0");
    }

    @Override
    public Mono<GroupCourseBooking> save(GroupCourseBooking booking) {
        GroupCourseBookingEntity entity = groupCourseConverter.toBookingEntity(booking);
        return groupCourseBookingDao.save(entity)
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Mono<GroupCourseBooking> update(GroupCourseBooking booking) {
        GroupCourseBookingEntity entity = groupCourseConverter.toBookingEntity(booking);
        return groupCourseBookingDao.save(entity)
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Mono<Integer> updateStatus(Long bookingId, String status) {
        java.time.LocalDateTime now = java.time.LocalDateTime.now();
        java.time.LocalDateTime cancelTime = "1".equals(status) ? now : null;
        return groupCourseBookingDao.updateStatus(bookingId, status, cancelTime, now);
    }

    @Override
    public Mono<Void> deleteById(Long bookingId) {
        return groupCourseBookingDao.softDelete(bookingId, java.time.LocalDateTime.now()).then();
    }

    @Override
    public Flux<GroupCourseBooking> findByMemberCardRecordId(Long memberCardRecordId) {
        return groupCourseBookingDao.findByMemberCardRecordIdAndDeletedAtIsNull(memberCardRecordId)
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Flux<GroupCourseBooking> findConflictingBookings(Long memberId, java.time.LocalDateTime newStartTime, java.time.LocalDateTime newEndTime) {
        return groupCourseBookingDao.findConflictingBookings(memberId, newStartTime, newEndTime)
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Flux<GroupCourseBooking> findAbsentMembers() {
        return groupCourseBookingDao.findAbsentMembers()
                .map(groupCourseConverter::toBookingDomain);
    }

    @Override
    public Mono<Integer> updateToAbsent(Long bookingId) {
        java.time.LocalDateTime now = java.time.LocalDateTime.now();
        return groupCourseBookingDao.updateToAbsent(bookingId, now);
    }
}