package com.campus.activity.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.campus.activity.common.ResultCode;
import com.campus.activity.dto.request.*;
import com.campus.activity.entity.Activity;
import com.campus.activity.entity.Registration;
import com.campus.activity.entity.User;
import com.campus.activity.exception.BusinessException;
import com.campus.activity.mapper.ActivityMapper;
import com.campus.activity.mapper.RegistrationMapper;
import com.campus.activity.mapper.UserMapper;
import com.campus.activity.service.ActivityService;
import com.campus.activity.service.AuthService;
import com.campus.activity.vo.ActivityVO;
import com.campus.activity.vo.ConflictCheckVO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class ActivityServiceImpl implements ActivityService {

    private final ActivityMapper activityMapper;
    private final UserMapper userMapper;
    private final RegistrationMapper registrationMapper;
    private final AuthService authService;

    @Override
    public IPage<ActivityVO> pageActivities(Page<Activity> page,
                                            Integer status,
                                            String keyword,
                                            String category,
                                            LocalDateTime startDate,
                                            LocalDateTime endDate) {
        IPage<Activity> activityPage = activityMapper.selectActivityPage(page, status, keyword, category, startDate, endDate);

        return activityPage.convert(activity -> {
            ActivityVO vo = convertToVO(activity);
            return vo;
        });
    }

    @Override
    public ActivityVO getActivityById(Long id) {
        Activity activity = activityMapper.selectById(id);
        if (activity == null || activity.getDeleted() == 1) {
            throw new BusinessException(ResultCode.ACTIVITY_NOT_FOUND);
        }

        ActivityVO vo = convertToVO(activity);

        try {
            User currentUser = authService.getCurrentUser();
            Registration registration = registrationMapper.selectOne(
                    new LambdaQueryWrapper<Registration>()
                            .eq(Registration::getUserId, currentUser.getId())
                            .eq(Registration::getActivityId, id)
                            .in(Registration::getStatus, 1, 2)
            );
            vo.setIsRegistered(registration != null);
        } catch (Exception e) {
            vo.setIsRegistered(false);
        }

        return vo;
    }

    @Override
    @Transactional
    public Long createActivity(ActivityCreateRequest request) {
        User currentUser = authService.getCurrentUser();
        if (currentUser.getRole() != 1) {
            throw new BusinessException(ResultCode.FORBIDDEN);
        }

        if (request.getStartTime().isAfter(request.getEndTime())) {
            throw new BusinessException(ResultCode.BAD_REQUEST.getCode(), "开始时间不能晚于结束时间");
        }

        ConflictCheckVO conflictCheck = checkConflict(CheckConflictRequest.builder()
                .startTime(request.getStartTime())
                .endTime(request.getEndTime())
                .build());

        if (conflictCheck.getHasConflict()) {
            throw new BusinessException(ResultCode.ACTIVITY_TIME_CONFLICT);
        }

        Activity activity = new Activity();
        BeanUtils.copyProperties(request, activity);
        activity.setAdminId(currentUser.getId());
        activity.setCurrentParticipants(0);
        activity.setStatus(0);

        if (request.getRegistrationDeadline() == null) {
            activity.setRegistrationDeadline(request.getStartTime());
        }

        activityMapper.insert(activity);

        return activity.getId();
    }

    @Override
    @Transactional
    public void updateActivity(Long id, ActivityUpdateRequest request) {
        User currentUser = authService.getCurrentUser();
        if (currentUser.getRole() != 1) {
            throw new BusinessException(ResultCode.FORBIDDEN);
        }

        Activity activity = activityMapper.selectById(id);
        if (activity == null || activity.getDeleted() == 1) {
            throw new BusinessException(ResultCode.ACTIVITY_NOT_FOUND);
        }

        if (!activity.getAdminId().equals(currentUser.getId())) {
            throw new BusinessException(ResultCode.FORBIDDEN);
        }

        if (request.getStartTime().isAfter(request.getEndTime())) {
            throw new BusinessException(ResultCode.BAD_REQUEST.getCode(), "开始时间不能晚于结束时间");
        }

        ConflictCheckVO conflictCheck = checkConflict(CheckConflictRequest.builder()
                .startTime(request.getStartTime())
                .endTime(request.getEndTime())
                .excludeActivityId(id)
                .build());

        if (conflictCheck.getHasConflict()) {
            throw new BusinessException(ResultCode.ACTIVITY_TIME_CONFLICT);
        }

        BeanUtils.copyProperties(request, activity);
        activityMapper.updateById(activity);
    }

    @Override
    @Transactional
    public void deleteActivity(Long id) {
        User currentUser = authService.getCurrentUser();
        if (currentUser.getRole() != 1) {
            throw new BusinessException(ResultCode.FORBIDDEN);
        }

        Activity activity = activityMapper.selectById(id);
        if (activity == null || activity.getDeleted() == 1) {
            throw new BusinessException(ResultCode.ACTIVITY_NOT_FOUND);
        }

        if (!activity.getAdminId().equals(currentUser.getId())) {
            throw new BusinessException(ResultCode.FORBIDDEN);
        }

        activityMapper.deleteById(id);
    }

    @Override
    public List<ActivityVO> getCalendarActivities(Integer year, Integer month) {
        List<Activity> activities = activityMapper.selectCalendarActivities(year, month);
        return activities.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    public ConflictCheckVO checkConflict(CheckConflictRequest request) {
        if (request.getStartTime().isAfter(request.getEndTime())) {
            throw new BusinessException(ResultCode.BAD_REQUEST.getCode(), "开始时间不能晚于结束时间");
        }

        List<Activity> conflictActivities = activityMapper.selectConflictActivities(
                request.getStartTime(),
                request.getEndTime(),
                request.getExcludeActivityId()
        );

        return ConflictCheckVO.builder()
                .hasConflict(!conflictActivities.isEmpty())
                .conflictActivities(conflictActivities.stream()
                        .map(activity -> ConflictCheckVO.ConflictActivity.builder()
                                .id(activity.getId())
                                .title(activity.getTitle())
                                .startTime(activity.getStartTime())
                                .endTime(activity.getEndTime())
                                .build())
                        .collect(Collectors.toList()))
                .build();
    }

    private ActivityVO convertToVO(Activity activity) {
        User admin = userMapper.selectById(activity.getAdminId());

        return ActivityVO.builder()
                .id(activity.getId())
                .title(activity.getTitle())
                .description(activity.getDescription())
                .coverImage(activity.getCoverImage())
                .startTime(activity.getStartTime())
                .endTime(activity.getEndTime())
                .registrationDeadline(activity.getRegistrationDeadline())
                .location(activity.getLocation())
                .maxParticipants(activity.getMaxParticipants())
                .currentParticipants(activity.getCurrentParticipants())
                .status(activity.getStatus())
                .category(activity.getCategory())
                .adminId(activity.getAdminId())
                .adminName(admin != null ? admin.getName() : null)
                .averageRating(activity.getAverageRating())
                .reviewCount(activity.getReviewCount())
                .createdAt(activity.getCreatedAt())
                .build();
    }
}