package com.lesingle.edu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lesingle.edu.common.enums.ErrorCode;
import com.lesingle.edu.common.enums.GenericStatus;
import com.lesingle.edu.common.exception.BusinessException;
import com.lesingle.edu.dto.request.TeacherCreateRequest;
import com.lesingle.edu.dto.request.TeacherUpdateRequest;
import com.lesingle.edu.dto.response.TeacherResponse;
import com.lesingle.edu.entity.ClassTeacher;
import com.lesingle.edu.entity.Clazz;
import com.lesingle.edu.entity.Lesson;
import com.lesingle.edu.entity.Teacher;
import com.lesingle.edu.mapper.ClassTeacherMapper;
import com.lesingle.edu.mapper.ClazzMapper;
import com.lesingle.edu.mapper.LessonMapper;
import com.lesingle.edu.mapper.TeacherMapper;
import com.lesingle.edu.service.ClassService;
import com.lesingle.edu.service.TeacherService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 教师服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TeacherServiceImpl extends com.baomidou.mybatisplus.extension.service.impl.ServiceImpl<TeacherMapper, Teacher>
    implements TeacherService {

    private final TeacherMapper teacherMapper;
    private final com.lesingle.edu.common.mapper.TeacherMapper teacherVoMapper;
    private final ClassTeacherMapper classTeacherMapper;
    private final ClazzMapper clazzMapper;
    private final LessonMapper lessonMapper;
    private final ClassService classService;
    private final PasswordEncoder passwordEncoder;

    @Override
    @Transactional
    public Teacher createTeacher(Long tenantId, TeacherCreateRequest request) {
        log.info("开始创建教师，用户名：{}", request.getUsername());

        // 检查用户名是否已存在
        Teacher existing = teacherMapper.selectOne(
                new LambdaQueryWrapper<Teacher>().eq(Teacher::getUsername, request.getUsername())
        );
        if (existing != null) {
            log.warn("用户名已存在：{}", request.getUsername());
            throw new BusinessException(ErrorCode.DATA_ALREADY_EXISTS, "用户名已存在");
        }

        // 检查手机号是否已存在
        checkPhoneUnique(tenantId, request.getPhone(), null);

        Teacher teacher = new Teacher();
        teacher.setTenantId(tenantId);
        teacher.setUsername(request.getUsername());
        teacher.setPassword(passwordEncoder.encode(request.getPassword()));
        teacher.setName(request.getName());
        teacher.setPhone(request.getPhone());
        teacher.setEmail(request.getEmail());
        teacher.setGender(request.getGender());
        teacher.setBio(request.getBio());
        teacher.setStatus(GenericStatus.ACTIVE.getCode());

        teacherMapper.insert(teacher);

        // 分配教师到班级
        if (!CollectionUtils.isEmpty(request.getClassIds())) {
            for (Long classId : request.getClassIds()) {
                classService.getClassByIdWithTenantCheck(classId, tenantId);
                ClassTeacher classTeacher = new ClassTeacher();
                classTeacher.setClassId(classId);
                classTeacher.setTeacherId(teacher.getId());
                classTeacher.setRole("MAIN");
                classTeacherMapper.insert(classTeacher);
            }
        }

        log.info("教师创建成功，ID: {}", teacher.getId());
        return teacher;
    }

    @Override
    @Transactional
    public Teacher updateTeacher(Long id, TeacherUpdateRequest request) {
        log.info("开始更新教师，ID: {}", id);

        Teacher teacher = getTeacherById(id);

        // 检查手机号是否已存在（排除当前教师）
        checkPhoneUnique(teacher.getTenantId(), request.getPhone(), teacher.getId());

        if (StringUtils.hasText(request.getName())) {
            teacher.setName(request.getName());
        }
        if (request.getPhone() != null) {
            teacher.setPhone(request.getPhone());
        }
        if (request.getEmail() != null) {
            teacher.setEmail(request.getEmail());
        }
        if (request.getAvatarUrl() != null) {
            teacher.setAvatarUrl(request.getAvatarUrl());
        }
        if (request.getGender() != null) {
            teacher.setGender(request.getGender());
        }
        if (request.getBio() != null) {
            teacher.setBio(request.getBio());
        }
        if (StringUtils.hasText(request.getStatus())) {
            if (!request.getStatus().equals(teacher.getStatus())) {
                log.info("教师状态变更：ID={}, name={}, oldStatus={}, newStatus={}",
                        teacher.getId(), teacher.getName(), teacher.getStatus(), request.getStatus());
            }
            teacher.setStatus(request.getStatus());
        }

        teacherMapper.updateById(teacher);

        // 更新教师班级分配
        if (request.getClassIds() != null) {
            classTeacherMapper.delete(
                    new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getTeacherId, id)
            );
            for (Long classId : request.getClassIds()) {
                classService.getClassByIdWithTenantCheck(classId, teacher.getTenantId());
                ClassTeacher classTeacher = new ClassTeacher();
                classTeacher.setClassId(classId);
                classTeacher.setTeacherId(id);
                classTeacher.setRole("MAIN");
                classTeacherMapper.insert(classTeacher);
            }
        }

        log.info("教师更新成功，ID: {}", id);
        return teacher;
    }

    @Override
    @Transactional
    public Teacher updateTeacherWithTenantCheck(Long id, Long tenantId, TeacherUpdateRequest request) {
        log.info("开始更新教师（带租户验证），ID: {}, tenantId: {}", id, tenantId);
        getTeacherByIdWithTenantCheck(id, tenantId);
        return updateTeacher(id, request);
    }

    @Override
    public Teacher getTeacherById(Long id) {
        log.debug("查询教师，ID: {}", id);

        Teacher teacher = teacherMapper.selectById(id);
        if (teacher == null) {
            log.warn("教师不存在，ID: {}", id);
            throw new BusinessException(ErrorCode.USER_NOT_FOUND, "教师不存在");
        }
        return teacher;
    }

    @Override
    public Teacher findTeacherById(Long id) {
        if (id == null) return null;
        return teacherMapper.selectById(id);
    }

    @Override
    public Teacher getTeacherByIdWithTenantCheck(Long id, Long tenantId) {
        log.debug("查询教师（带租户验证），ID: {}, tenantId: {}", id, tenantId);
        Teacher teacher = getTeacherById(id);
        if (!teacher.getTenantId().equals(tenantId)) {
            log.warn("租户无权访问教师，教师ID: {}, 租户ID: {}", id, tenantId);
            throw new BusinessException(ErrorCode.FORBIDDEN, "无权访问该教师");
        }
        return teacher;
    }

    @Override
    public Page<Teacher> getTeacherPage(Long tenantId, Integer pageNum, Integer pageSize, String keyword, String status) {
        // 设置默认分页参数
        if (pageNum == null || pageNum <= 0) {
            pageNum = 1;
        }
        if (pageSize == null || pageSize <= 0) {
            pageSize = 10;
        }

        log.debug("分页查询教师，页码：{}，每页数量：{}", pageNum, pageSize);

        Page<Teacher> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Teacher> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(Teacher::getTenantId, tenantId);

        if (StringUtils.hasText(keyword)) {
            wrapper.and(w -> w
                    .like(Teacher::getName, keyword)
                    .or()
                    .like(Teacher::getUsername, keyword)
                    .or()
                    .like(Teacher::getPhone, keyword)
            );
        }
        if (StringUtils.hasText(status)) {
            wrapper.eq(Teacher::getStatus, status);
        }
        wrapper.orderByDesc(Teacher::getCreatedAt);

        return teacherMapper.selectPage(page, wrapper);
    }

    @Override
    @Transactional
    public void deleteTeacher(Long id) {
        log.info("开始删除教师，ID: {}", id);

        getTeacherById(id);
        teacherMapper.deleteById(id);

        log.info("教师删除成功，ID: {}", id);
    }

    @Override
    @Transactional
    public void deleteTeacherWithTenantCheck(Long id, Long tenantId) {
        log.info("开始删除教师（带租户验证），ID: {}, tenantId: {}", id, tenantId);
        getTeacherByIdWithTenantCheck(id, tenantId);
        deleteTeacher(id);
    }

    @Override
    @Transactional
    public void resetPassword(Long id, String newPassword) {
        log.info("开始重置密码，ID: {}", id);

        Teacher teacher = getTeacherById(id);
        teacher.setPassword(passwordEncoder.encode(newPassword));
        teacherMapper.updateById(teacher);

        log.info("密码重置成功，ID: {}", id);
    }

    @Override
    @Transactional
    public void resetPasswordWithTenantCheck(Long id, Long tenantId, String newPassword) {
        log.info("开始重置密码（带租户验证），ID: {}, tenantId: {}", id, tenantId);
        getTeacherByIdWithTenantCheck(id, tenantId);
        resetPassword(id, newPassword);
    }

    @Override
    @Transactional
    public String resetPasswordAndReturnTemp(Long id, Long tenantId) {
        log.info("开始重置密码并返回临时密码，ID: {}, tenantId: {}", id, tenantId);
        Teacher teacher = getTeacherByIdWithTenantCheck(id, tenantId);
        String tempPassword = UUID.randomUUID().toString().replace("-", "").substring(0, 8);
        teacher.setPassword(passwordEncoder.encode(tempPassword));
        teacherMapper.updateById(teacher);
        log.info("密码重置成功，ID: {}", id);
        return tempPassword;
    }

    @Override
    public List<Teacher> getTeachersByIds(List<Long> teacherIds) {
        log.debug("根据 ID 列表查询教师，ID 列表：{}", teacherIds);

        if (teacherIds == null || teacherIds.isEmpty()) {
            return List.of();
        }

        LambdaQueryWrapper<Teacher> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Teacher::getId, teacherIds)
                .eq(Teacher::getStatus, GenericStatus.ACTIVE.getCode());

        return teacherMapper.selectList(wrapper);
    }

    @Override
    public TeacherResponse toTeacherResponse(Teacher teacher) {
        if (teacher == null) return null;
        TeacherResponse response = teacherVoMapper.toVO(teacher);
        enrichTeacherResponse(response, teacher.getId());
        return response;
    }

    @Override
    public List<TeacherResponse> toTeacherResponseList(List<Teacher> teachers) {
        if (teachers == null) return null;
        List<TeacherResponse> list = new ArrayList<>(teachers.size());
        for (Teacher teacher : teachers) {
            list.add(toTeacherResponse(teacher));
        }
        return list;
    }

    private void enrichTeacherResponse(TeacherResponse response, Long teacherId) {
        List<ClassTeacher> classTeachers = classTeacherMapper.selectList(
                new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getTeacherId, teacherId)
        );
        List<Long> classIds = new ArrayList<>();
        List<String> classNames = new ArrayList<>();
        for (ClassTeacher ct : classTeachers) {
            classIds.add(ct.getClassId());
            Clazz clazz = clazzMapper.selectById(ct.getClassId());
            if (clazz != null) {
                classNames.add(clazz.getName());
            }
        }
        response.setClassIds(classIds);
        response.setClassNames(classNames.isEmpty() ? null : classNames);

        if (GenericStatus.ACTIVE.getCode().equals(response.getStatus())) {
            response.setStatus(GenericStatus.ACTIVE.getCode());
        }

        long lessonCount = 0;
        try {
            lessonCount = lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>().eq(Lesson::getTeacherId, teacherId)
            );
        } catch (Exception e) {
            log.debug("Query lesson count failed: {}", e.getMessage());
        }
        response.setLessonCount((int) lessonCount);
    }

    /**
     * 检查手机号唯一性
     *
     * @param tenantId 租户 ID
     * @param phone 手机号
     * @param excludeTeacherId 排除的教师 ID（编辑时使用，新增时为 null）
     * @throws BusinessException 手机号已存在时抛出
     */
    private void checkPhoneUnique(Long tenantId, String phone, Long excludeTeacherId) {
        if (!StringUtils.hasText(phone)) {
            return; // 手机号为空时不校验（由 @NotBlank 校验）
        }

        LambdaQueryWrapper<Teacher> wrapper = new LambdaQueryWrapper<Teacher>()
                .eq(Teacher::getTenantId, tenantId)
                .eq(Teacher::getPhone, phone);

        // 编辑时排除当前教师
        if (excludeTeacherId != null) {
            wrapper.ne(Teacher::getId, excludeTeacherId);
        }

        Teacher existing = teacherMapper.selectOne(wrapper);
        if (existing != null) {
            log.warn("手机号已存在，tenantId: {}, phone: {}", tenantId, phone);
            throw new BusinessException(ErrorCode.DATA_ALREADY_EXISTS, "手机号已存在");
        }
    }

}
