package rd.service.user;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yitter.idgen.YitIdHelper;
import rd.dao.mapper.user.TeacherInfoMapper;
import rd.data.code.ServiceCode;
import rd.data.dto.user.UserBasicInfoDTO;
import rd.data.dto.user.teacher.TeacherUserDTO;
import rd.data.dto.user.teacher.TeacherUserInfoDTO;
import rd.data.db.table.TeacherInfo;
import rd.data.enums.UserType;
import rd.data.model.response.PaginationWrapper;
import rd.exception.ServiceException;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class TeacherUserService {
    private final TeacherInfoMapper teacherInfoMapper;

    private final UserBasicService userBasicService;
    private final UserInfoService userInfoService;

    public TeacherUserService(TeacherInfoMapper teacherInfoMapper,
                              UserBasicService userBasicService,
                              UserInfoService userInfoService) {
        this.teacherInfoMapper = teacherInfoMapper;
        this.userBasicService = userBasicService;
        this.userInfoService = userInfoService;
    }

    public PaginationWrapper<List<TeacherInfo>> list(int page, int pageSize) {
        if (pageSize == 0) {
            pageSize = 1024;
        }

        Page<TeacherInfo> queryPage = new Page<>(page, pageSize);
        var result = teacherInfoMapper.selectPage(queryPage, new QueryWrapper<TeacherInfo>()
                .select("id, name, create_time, edit_time")
                .eq("deleted", false)
        );

        return new PaginationWrapper<>(
                (int) result.getCurrent(),
                (int) result.getSize(),
                (int) result.getTotal(),
                result.getRecords()
        );
    }

    public TeacherInfo getInfo(Long id) {
        var result = teacherInfoMapper.selectOne(new QueryWrapper<TeacherInfo>()
                .select("id, name, create_time, edit_time")
                .eq("id", id)
                .eq("deleted", false)
        );

        if (result == null) {
            throw ServiceException.error(ServiceCode.UserNotExists);
        }

        return result;
    }

    public TeacherUserInfoDTO getUserInfoById(Long id) {
        var result = teacherInfoMapper.selectOne(new QueryWrapper<TeacherInfo>()
                .select("id, name, create_time, edit_time")
                .eq("id", id)
                .eq("deleted", false)
        );

        var userBasic = userBasicService.getUserBasicById(id);

        if (result == null || userBasic == null) {
            throw ServiceException.error(ServiceCode.UserNotExists);
        }

        return new TeacherUserInfoDTO(id, userBasic.getUsername(), result.getName());
    }

    public List<TeacherInfo> getInfoById(List<Long> ids) {
        if (ids.isEmpty()) {
            return new ArrayList<>();
        }

        return userInfoService.getAsTeacher(ids);
    }

    @Transactional
    public TeacherInfo add(TeacherUserDTO dto) {
        Long id = YitIdHelper.nextId();

        TeacherInfo teacherInfo = new TeacherInfo();
        teacherInfo.setId(id);
        teacherInfo.setName(dto.teacherName());

        teacherInfoMapper.insert(teacherInfo);

        String username = (dto.username() == null) ? teacherInfo.getId().toString() : dto.username();
        String password = dto.password();
        userBasicService.addUser(id, username, password, (short) UserType.TEACHER.code);

        return userInfoService.getAsTeacher(id, false);
    }

    @Transactional
    public void delete(Long id) {
        TeacherInfo teacherInfo = new TeacherInfo();
        teacherInfo.setDeleted(true);

        teacherInfoMapper.update(teacherInfo, new QueryWrapper<TeacherInfo>()
                .eq("id", id)
        );

        userBasicService.deleteUser(id);
        userInfoService.invalidateCache(id);
    }

    @Transactional
    public TeacherInfo update(Long id, TeacherUserDTO dto) {
        TeacherInfo teacherInfo = this.getInfo(id);
        teacherInfo.setName(dto.teacherName());
        teacherInfo.setEditTime(LocalDateTime.now());

        teacherInfoMapper.update(teacherInfo, new QueryWrapper<TeacherInfo>()
                .eq("id", id)
                .eq("deleted", false)
        );

        UserBasicInfoDTO userBasicInfoDTO = new UserBasicInfoDTO(id, dto.username(), dto.password(), (short) UserType.TEACHER.code);
        userBasicService.updateUser(id, userBasicInfoDTO);

        return userInfoService.getAsTeacher(id, false);
    }
}
