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.ScanCheckInRequest;
import com.campus.activity.dto.request.TicketCheckInRequest;
import com.campus.activity.entity.Activity;
import com.campus.activity.entity.CheckIn;
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.CheckInMapper;
import com.campus.activity.mapper.RegistrationMapper;
import com.campus.activity.service.AuthService;
import com.campus.activity.service.CheckInService;
import com.campus.activity.util.QrCodeUtil;
import com.campus.activity.vo.CheckInVO;
import com.campus.activity.vo.QrCodeVO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Service
@RequiredArgsConstructor
public class CheckInServiceImpl implements CheckInService {

    private final CheckInMapper checkInMapper;
    private final RegistrationMapper registrationMapper;
    private final ActivityMapper activityMapper;
    private final AuthService authService;

    @Override
    public QrCodeVO generateQrCode(Long activityId) {
        User currentUser = authService.getCurrentUser();
        if (currentUser.getRole() != 1) {
            throw new BusinessException(ResultCode.FORBIDDEN);
        }

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

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

        String qrCodeContent = QrCodeUtil.generateQrCodeContent(activityId);
        LocalDateTime expiresAt = activity.getEndTime();

        return QrCodeVO.builder()
                .qrCodeContent(qrCodeContent)
                .expiresAt(expiresAt)
                .build();
    }

    @Override
    @Transactional
    public CheckInVO scanCheckIn(ScanCheckInRequest request) {
        User currentUser = authService.getCurrentUser();

        Long activityId = QrCodeUtil.parseActivityIdFromQrCode(request.getQrCodeContent());
        if (activityId == null) {
            throw new BusinessException(ResultCode.BAD_REQUEST.getCode(), "二维码无效");
        }

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

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime earlyCheckInTime = activity.getStartTime().minusHours(1);
        if (now.isBefore(earlyCheckInTime) || now.isAfter(activity.getEndTime())) {
            throw new BusinessException(ResultCode.CHECKIN_TIME_EXPIRED);
        }

        Registration registration = registrationMapper.selectOne(
                new LambdaQueryWrapper<Registration>()
                        .eq(Registration::getUserId, currentUser.getId())
                        .eq(Registration::getActivityId, activityId)
                        .eq(Registration::getStatus, 1)
        );

        if (registration == null) {
            throw new BusinessException(ResultCode.NOT_REGISTERED);
        }

        CheckIn existingCheckIn = checkInMapper.selectOne(
                new LambdaQueryWrapper<CheckIn>()
                        .eq(CheckIn::getRegistrationId, registration.getId())
        );

        if (existingCheckIn != null) {
            throw new BusinessException(ResultCode.ALREADY_CHECKED_IN);
        }

        return performCheckIn(registration, currentUser, activityId, 0);
    }

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

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

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

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime earlyCheckInTime = activity.getStartTime().minusHours(1);
        if (now.isBefore(earlyCheckInTime) || now.isAfter(activity.getEndTime())) {
            throw new BusinessException(ResultCode.CHECKIN_TIME_EXPIRED);
        }

        Registration registration = registrationMapper.selectByTicketCode(request.getTicketCode());
        if (registration == null) {
            throw new BusinessException(ResultCode.BAD_REQUEST.getCode(), "电子票无效");
        }

        if (!registration.getActivityId().equals(request.getActivityId())) {
            throw new BusinessException(ResultCode.BAD_REQUEST.getCode(), "电子票与活动不匹配");
        }

        CheckIn existingCheckIn = checkInMapper.selectOne(
                new LambdaQueryWrapper<CheckIn>()
                        .eq(CheckIn::getRegistrationId, registration.getId())
        );

        if (existingCheckIn != null) {
            throw new BusinessException(ResultCode.ALREADY_CHECKED_IN);
        }

        User student = authService.getUserById(registration.getUserId());

        return performCheckIn(registration, student, request.getActivityId(), 1);
    }

    @Override
    public IPage<CheckInVO> getActivityCheckIns(Page<CheckIn> page, Long activityId) {
        return checkInMapper.selectActivityCheckIns(page, activityId);
    }

    private CheckInVO performCheckIn(Registration registration, User user, Long activityId, int method) {
        CheckIn checkIn = new CheckIn();
        checkIn.setRegistrationId(registration.getId());
        checkIn.setUserId(user.getId());
        checkIn.setActivityId(activityId);
        checkIn.setCheckInTime(LocalDateTime.now());
        checkIn.setCheckInMethod(method);

        checkInMapper.insert(checkIn);

        registration.setStatus(2);
        registrationMapper.updateById(registration);

        return convertToVO(checkIn, user);
    }

    private CheckInVO convertToVO(CheckIn checkIn, User user) {
        CheckInVO vo = new CheckInVO();
        BeanUtils.copyProperties(checkIn, vo);
        vo.setUserName(user.getName());
        vo.setStudentId(user.getStudentId());
        return vo;
    }
}