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.TenantPackageStatus;
import com.lesingle.edu.common.enums.TenantStatus;
import com.lesingle.edu.common.exception.BusinessException;
import com.lesingle.edu.dto.request.TenantCreateRequest;
import com.lesingle.edu.dto.request.TenantUpdateRequest;
import com.lesingle.edu.dto.response.TenantResponse;
import com.lesingle.edu.entity.CoursePackage;
import com.lesingle.edu.entity.Student;
import com.lesingle.edu.entity.Teacher;
import com.lesingle.edu.entity.Tenant;
import com.lesingle.edu.entity.TenantPackage;
import com.lesingle.edu.entity.CourseCollectionPackage;
import com.lesingle.edu.entity.SchedulePlan;
import com.lesingle.edu.entity.Clazz;
import com.lesingle.edu.entity.StudentRecord;
import com.lesingle.edu.entity.StudentClassHistory;
import com.lesingle.edu.mapper.StudentMapper;
import com.lesingle.edu.mapper.TeacherMapper;
import com.lesingle.edu.mapper.TenantMapper;
import com.lesingle.edu.mapper.TenantPackageMapper;
import com.lesingle.edu.mapper.SchedulePlanMapper;
import com.lesingle.edu.mapper.CourseCollectionPackageMapper;
import com.lesingle.edu.mapper.CourseCollectionMapper;
import com.lesingle.edu.mapper.ClazzMapper;
import com.lesingle.edu.entity.CourseCollection;
import com.lesingle.edu.service.CoursePackageService;
import com.lesingle.edu.service.TenantService;
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.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 租户服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TenantServiceImpl extends com.baomidou.mybatisplus.extension.service.impl.ServiceImpl<TenantMapper, Tenant>
    implements TenantService {

    private final TenantMapper tenantMapper;
    private final TenantPackageMapper tenantPackageMapper;
    private final CoursePackageService coursePackageService;
    private final CourseCollectionMapper collectionMapper;
    private final TeacherMapper teacherMapper;
    private final StudentMapper studentMapper;
    private final PasswordEncoder passwordEncoder;
    private final SchedulePlanMapper schedulePlanMapper;
    private final CourseCollectionPackageMapper collectionPackageMapper;
    private final ClazzMapper clazzMapper;

    @Override
    @Transactional
    public Tenant createTenant(TenantCreateRequest request) {
        log.info("开始创建租户，租户名称：{}", request.getName());

        // 检查租户代码是否已存在
        Tenant existing = tenantMapper.selectOne(
                new LambdaQueryWrapper<Tenant>().eq(Tenant::getCode, request.getCode())
        );
        if (existing != null) {
            log.warn("租户代码已存在：{}", request.getCode());
            throw new BusinessException(ErrorCode.DATA_ALREADY_EXISTS, "租户代码已存在");
        }

        // 构建实体
        Tenant tenant = new Tenant();
        tenant.setName(request.getName());
        tenant.setCode(request.getCode());
        tenant.setContactName(request.getContactName());
        tenant.setContactPhone(request.getContactPhone());
        tenant.setContactEmail(request.getContactEmail());
        tenant.setAddress(request.getAddress());
        tenant.setLogoUrl(request.getLogoUrl());

        // 设置有效期相关字段（兼容旧字段）
        tenant.setStartDate(request.getStartDate());
        tenant.setExpireDate(request.getExpireDate());

        tenant.setStatus(TenantStatus.ACTIVE.getCode());

        // 设置登录账号和密码（username 与 code 一致用于登录）
        tenant.setUsername(request.getCode());
        String rawPassword = StringUtils.hasText(request.getPassword()) ? request.getPassword() : "123456";
        tenant.setPassword(passwordEncoder.encode(rawPassword));

        // 设置配额和有效期默认值
        tenant.setTeacherQuota(request.getTeacherQuota() != null ? request.getTeacherQuota() : 20);
        tenant.setStudentQuota(request.getStudentQuota() != null ? request.getStudentQuota() : 200);
        tenant.setStartDate(request.getStartDate());
        tenant.setExpireDate(request.getExpireDate());

        // 使用 MP 的 insert 方法
        tenantMapper.insert(tenant);

        // 处理课程套餐关联（三层架构，支持多选）
        if (request.getCollectionIds() != null && !request.getCollectionIds().isEmpty()) {
            List<TenantPackage> tenantPackages = new ArrayList<>();
            for (Long collectionId : request.getCollectionIds()) {
                CourseCollection collection = collectionMapper.selectById(collectionId);
                if (collection == null) {
                    log.warn("课程套餐不存在，collectionId: {}", collectionId);
                    throw new BusinessException(ErrorCode.PACKAGE_NOT_FOUND, "课程套餐不存在：" + collectionId);
                }

                TenantPackage tenantPackage = new TenantPackage();
                tenantPackage.setTenantId(tenant.getId());
                tenantPackage.setCollectionId(collectionId);
                tenantPackage.setStartDate(request.getStartDate() != null ? request.getStartDate() : LocalDate.now());
                tenantPackage.setEndDate(request.getExpireDate());
                tenantPackage.setPricePaid(collection.getDiscountPrice() != null ? collection.getDiscountPrice() : collection.getPrice());
                tenantPackage.setStatus(TenantPackageStatus.ACTIVE);
                tenantPackages.add(tenantPackage);
            }

            // 批量插入套餐关联记录
            for (TenantPackage tp : tenantPackages) {
                tenantPackageMapper.insert(tp);
            }

            log.info("租户创建成功并关联 {} 个课程套餐，ID: {}, collectionIds: {}", tenantPackages.size(), tenant.getId(), request.getCollectionIds());
        } else {
            log.info("租户创建成功，ID: {}", tenant.getId());
        }

        return tenant;
    }

    @Override
    @Transactional
    public Tenant updateTenant(Long id, TenantUpdateRequest request) {
        log.info("开始更新租户，ID: {}", id);

        Tenant tenant = getTenantById(id);

        if (StringUtils.hasText(request.getName())) {
            tenant.setName(request.getName());
        }
        if (request.getContactName() != null) {
            tenant.setContactName(request.getContactName());
        }
        if (request.getContactPhone() != null) {
            tenant.setContactPhone(request.getContactPhone());
        }
        if (request.getContactEmail() != null) {
            tenant.setContactEmail(request.getContactEmail());
        }
        if (request.getAddress() != null) {
            tenant.setAddress(request.getAddress());
        }
        if (request.getLogoUrl() != null) {
            tenant.setLogoUrl(request.getLogoUrl());
        }
        if (StringUtils.hasText(request.getStatus())) {
            tenant.setStatus(request.getStatus());
        }
        if (request.getTeacherQuota() != null) {
            tenant.setTeacherQuota(request.getTeacherQuota());
        }
        if (request.getStudentQuota() != null) {
            tenant.setStudentQuota(request.getStudentQuota());
        }
        if (request.getStartDate() != null) {
            tenant.setStartDate(request.getStartDate());
        }
        if (request.getExpireDate() != null) {
            tenant.setExpireDate(request.getExpireDate());
        }

        // 处理课程套餐关联（三层架构，支持多选）
        if (request.getCollectionIds() != null) {
            LocalDate endDate = request.getExpireDate() != null ? request.getExpireDate() : tenant.getExpireDate();

            // 1. 获取现有的关联集合 ID（ACTIVE 状态）
            List<TenantPackage> existingPackages = tenantPackageMapper.selectList(
                    new LambdaQueryWrapper<TenantPackage>()
                            .eq(TenantPackage::getTenantId, id)
                            .eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
            );
            Set<Long> existingCollectionIds = existingPackages.stream()
                    .map(TenantPackage::getCollectionId)
                    .collect(Collectors.toSet());

            // 2. 计算被移除的套餐 ID（在 existingCollectionIds 中但不在 request.getCollectionIds() 中）
            Set<Long> removedCollectionIds = existingCollectionIds.stream()
                    .filter(collectionId -> !request.getCollectionIds().contains(collectionId))
                    .collect(Collectors.toSet());

            // 3. 检查被移除的套餐下是否有排课计划（用于提示用户）
            if (!removedCollectionIds.isEmpty() && (request.getForceRemove() == null || !request.getForceRemove())) {
                Map<String, Object> warnings = new HashMap<>();
                for (Long collectionId : removedCollectionIds) {
                    // 查询该套餐下所有课程包
                    List<Long> packageIds = collectionPackageMapper.selectList(
                        new LambdaQueryWrapper<CourseCollectionPackage>()
                            .eq(CourseCollectionPackage::getCollectionId, collectionId)
                    ).stream().map(CourseCollectionPackage::getPackageId).collect(Collectors.toList());

                    if (!packageIds.isEmpty()) {
                        // 查询该套餐下课程包的排课数量
                        long count = schedulePlanMapper.selectCount(
                            new LambdaQueryWrapper<SchedulePlan>()
                                .eq(SchedulePlan::getTenantId, id)
                                .in(SchedulePlan::getCoursePackageId, packageIds)
                        );
                        if (count > 0) {
                            // 获取套餐名称
                            CourseCollection collection = collectionMapper.selectById(collectionId);
                            Map<String, Object> packageWarning = new HashMap<>();
                            packageWarning.put("collectionId", collectionId);
                            packageWarning.put("collectionName", collection != null ? collection.getName() : "未知套餐");
                            packageWarning.put("scheduleCount", count);
                            warnings.put("package_" + collectionId, packageWarning);
                        }
                    }
                }

                // 如果有警告信息，抛出异常让前端显示确认弹窗
                if (!warnings.isEmpty()) {
                    List<Map<String, Object>> warningList = new ArrayList<>();
                    for (Object warning : warnings.values()) {
                        warningList.add((Map<String, Object>) warning);
                    }
                    throw new BusinessException(ErrorCode.REMOVE_PACKAGE_HAS_SCHEDULES,
                        "该套餐下有排课计划，无法删除", warningList);
                }
            }

            // 4. 将被移除的套餐关联状态改为 EXPIRED（不物理删除）
            for (Long collectionId : removedCollectionIds) {
                TenantPackage tenantPackage = existingPackages.stream()
                    .filter(tp -> tp.getCollectionId().equals(collectionId))
                    .findFirst()
                    .orElse(null);
                if (tenantPackage != null) {
                    tenantPackage.setStatus(TenantPackageStatus.EXPIRED);
                    tenantPackage.setUpdatedAt(LocalDateTime.now());
                    tenantPackageMapper.updateById(tenantPackage);
                    log.info("租户套餐关联已过期，tenantId={}, collectionId={}", id, collectionId);
                }
            }

            // 5. 获取更新后的关联集合 ID（用于创建新关联）
            Set<Long> currentCollectionIds = existingCollectionIds;

            // 6. 创建新的关联记录
            for (Long collectionId : request.getCollectionIds()) {
                if (!currentCollectionIds.contains(collectionId)) {
                    CourseCollection collection = collectionMapper.selectById(collectionId);
                    if (collection == null) {
                        log.warn("课程套餐不存在，collectionId: {}", collectionId);
                        throw new BusinessException(ErrorCode.PACKAGE_NOT_FOUND, "课程套餐不存在：" + collectionId);
                    }

                    TenantPackage tp = new TenantPackage();
                    tp.setTenantId(id);
                    tp.setCollectionId(collectionId);
                    tp.setStartDate(LocalDate.now());
                    tp.setEndDate(endDate);
                    tp.setStatus(TenantPackageStatus.ACTIVE);
                    tp.setPricePaid(collection.getDiscountPrice() != null ? collection.getDiscountPrice() : collection.getPrice());
                    tp.setCreatedAt(LocalDateTime.now());
                    tenantPackageMapper.insert(tp);
                    log.info("创建租户课程套餐关联，tenantId={}, collectionId={}", id, collectionId);
                }
            }

            // 7. 更新现有关联的结束日期
            for (TenantPackage tp : existingPackages) {
                if (request.getCollectionIds().contains(tp.getCollectionId())) {
                    tp.setEndDate(endDate);
                    tp.setUpdatedAt(LocalDateTime.now());
                    tenantPackageMapper.updateById(tp);
                }
            }

            log.info("更新租户课程套餐关联，tenantId={}, collectionIds={}", id, request.getCollectionIds());
        }

        tenantMapper.updateById(tenant);

        log.info("租户更新成功，ID: {}", id);
        return tenant;
    }

    @Override
    public Tenant getTenantById(Long id) {
        log.debug("查询租户，ID: {}", id);

        Tenant tenant = tenantMapper.selectById(id);
        if (tenant == null) {
            log.warn("租户不存在，ID: {}", id);
            throw new BusinessException(ErrorCode.TENANT_NOT_FOUND);
        }
        return tenant;
    }

    @Override
    public Page<Tenant> getTenantPage(Integer pageNum, Integer pageSize, String keyword, String status) {
        // 设置默认值，防止空指针
        int current = pageNum != null && pageNum > 0 ? pageNum : 1;
        int size = pageSize != null && pageSize > 0 ? pageSize : 10;
        log.debug("分页查询租户，页码：{}，每页数量：{}", current, size);

        Page<Tenant> page = new Page<>(current, size);
        LambdaQueryWrapper<Tenant> wrapper = new LambdaQueryWrapper<>();

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

        return tenantMapper.selectPage(page, wrapper);
    }

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

        Tenant tenant = getTenantById(id);

        // 清理租户套餐关联记录
        int deletedCount = tenantPackageMapper.delete(
                new LambdaQueryWrapper<TenantPackage>()
                        .eq(TenantPackage::getTenantId, id)
        );
        log.info("已清理租户套餐关联记录：tenantId={}, count={}", id, deletedCount);

        tenantMapper.deleteById(id);

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

    @Override
    public List<Tenant> getAllActiveTenants() {
        log.debug("查询所有活跃租户");

        List<Tenant> tenants = tenantMapper.selectList(
                new LambdaQueryWrapper<Tenant>()
                        .eq(Tenant::getStatus, TenantStatus.ACTIVE.getCode())
                        .orderByAsc(Tenant::getName)
        );
        return tenants;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTenantStatus(Long id, String status) {
        log.info("开始更新租户状态，ID: {}, status: {}", id, status);

        Tenant tenant = getTenantById(id);

        // 验证状态值
        TenantStatus targetStatus;
        try {
            targetStatus = TenantStatus.fromCode(status);
        } catch (Exception e) {
            log.warn("无效的租户状态值：{}", status);
            throw new BusinessException(ErrorCode.INVALID_PARAMETER, "无效的租户状态");
        }

        tenant.setStatus(targetStatus.getCode());
        tenantMapper.updateById(tenant);

        log.info("租户状态更新成功，ID: {}, status: {}", id, status);
    }

    @Override
    public Page<TenantResponse> getTenantPageWithStats(Integer pageNum, Integer pageSize, String keyword, String status) {
        log.debug("分页查询租户（带统计），页码：{}，每页数量：{}", pageNum, pageSize);

        // 先查询租户分页数据
        Page<Tenant> tenantPage = getTenantPage(pageNum, pageSize, keyword, status);

        // 转换为 TenantResponse 并填充统计信息
        List<TenantResponse> responses = tenantPage.getRecords().stream()
                .map(this::toResponseWithStats)
                .collect(Collectors.toList());

        // 构建返回的分页对象
        Page<TenantResponse> resultPage = new Page<>(tenantPage.getCurrent(), tenantPage.getSize(), tenantPage.getTotal());
        resultPage.setRecords(responses);

        return resultPage;
    }

    /**
     * 将 Tenant 实体转换为 TenantResponse（带教师和学生统计）
     */
    private TenantResponse toResponseWithStats(Tenant tenant) {
        // 查询教师数量
        Long teacherCount = teacherMapper.selectCount(
                new LambdaQueryWrapper<Teacher>()
                        .eq(Teacher::getTenantId, tenant.getId())
        );

        // 查询学生数量
        Long studentCount = studentMapper.selectCount(
                new LambdaQueryWrapper<Student>()
                        .eq(Student::getTenantId, tenant.getId())
        );

        // 从 tenant_package 表查询所有套餐信息（只查询 ACTIVE 状态的关联）
        List<TenantPackage> tenantPackages = tenantPackageMapper.selectList(
                new LambdaQueryWrapper<TenantPackage>()
                        .eq(TenantPackage::getTenantId, tenant.getId())
                        .eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
                        .orderByDesc(TenantPackage::getStartDate)
        );

        // 获取所有关联的套餐名称列表
        List<String> packageNames = new ArrayList<>();
        for (TenantPackage tp : tenantPackages) {
            if (tp.getCollectionId() != null) {
                CourseCollection collection = collectionMapper.selectById(tp.getCollectionId());
                if (collection != null) {
                    packageNames.add(collection.getName());
                }
            }
        }

        return TenantResponse.builder()
                .id(tenant.getId())
                .name(tenant.getName())
                .code(tenant.getCode())
                .username(tenant.getUsername())
                .contactName(tenant.getContactName())
                .contactPhone(tenant.getContactPhone())
                .contactEmail(tenant.getContactEmail())
                .address(tenant.getAddress())
                .logoUrl(tenant.getLogoUrl())
                .status(tenant.getStatus())
                .expireAt(tenant.getExpireAt())
                .maxStudents(tenant.getMaxStudents())
                .maxTeachers(tenant.getMaxTeachers())
                .packageNames(packageNames)  // 套餐名称列表
                .teacherQuota(tenant.getTeacherQuota())
                .studentQuota(tenant.getStudentQuota())
                .storageQuota(tenant.getStorageQuota())
                .storageUsed(tenant.getStorageUsed())
                .teacherCount(teacherCount != null ? teacherCount.intValue() : 0)
                .studentCount(studentCount != null ? studentCount.intValue() : 0)
                .startDate(tenant.getStartDate())
                .expireDate(tenant.getExpireDate())
                .createdAt(tenant.getCreatedAt())
                .updatedAt(tenant.getUpdatedAt())
                .build();
    }

    /**
     * 构建租户详情响应（包含完整统计信息和列表）
     */
    private TenantResponse buildTenantResponse(Tenant tenant) {
        // 查询班级数量
        Long classCount = clazzMapper.selectCount(
                new LambdaQueryWrapper<Clazz>()
                        .eq(Clazz::getTenantId, tenant.getId())
        );

        // 查询授课数量（基于 schedule_plan 表）
        Long lessonCount = schedulePlanMapper.selectCount(
                new LambdaQueryWrapper<SchedulePlan>()
                        .eq(SchedulePlan::getTenantId, tenant.getId())
        );

        // 查询教师数量
        Long teacherCount = teacherMapper.selectCount(
                new LambdaQueryWrapper<Teacher>()
                        .eq(Teacher::getTenantId, tenant.getId())
        );

        // 查询学生数量
        Long studentCount = studentMapper.selectCount(
                new LambdaQueryWrapper<Student>()
                        .eq(Student::getTenantId, tenant.getId())
        );

        // 从 tenant_package 表查询所有套餐信息（只查询 ACTIVE 状态的关联）
        List<TenantPackage> tenantPackages = tenantPackageMapper.selectList(
                new LambdaQueryWrapper<TenantPackage>()
                        .eq(TenantPackage::getTenantId, tenant.getId())
                        .eq(TenantPackage::getStatus, TenantPackageStatus.ACTIVE)
                        .orderByDesc(TenantPackage::getStartDate)
        );

        // 获取所有关联的套餐名称列表
        List<String> packageNames = new ArrayList<>();
        for (TenantPackage tp : tenantPackages) {
            if (tp.getCollectionId() != null) {
                CourseCollection collection = collectionMapper.selectById(tp.getCollectionId());
                if (collection != null) {
                    packageNames.add(collection.getName());
                }
            }
        }

        return TenantResponse.builder()
                .id(tenant.getId())
                .name(tenant.getName())
                .code(tenant.getCode())
                .username(tenant.getUsername())
                .contactName(tenant.getContactName())
                .contactPhone(tenant.getContactPhone())
                .contactEmail(tenant.getContactEmail())
                .address(tenant.getAddress())
                .logoUrl(tenant.getLogoUrl())
                .status(tenant.getStatus())
                .expireAt(tenant.getExpireAt())
                .maxStudents(tenant.getMaxStudents())
                .maxTeachers(tenant.getMaxTeachers())
                .packageNames(packageNames)
                .teacherQuota(tenant.getTeacherQuota())
                .studentQuota(tenant.getStudentQuota())
                .storageQuota(tenant.getStorageQuota())
                .storageUsed(tenant.getStorageUsed())
                .teacherCount(teacherCount != null ? teacherCount.intValue() : 0)
                .studentCount(studentCount != null ? studentCount.intValue() : 0)
                .classCount(classCount != null ? classCount.intValue() : 0)
                .lessonCount(lessonCount != null ? lessonCount.intValue() : 0)
                .startDate(tenant.getStartDate())
                .expireDate(tenant.getExpireDate())
                .createdAt(tenant.getCreatedAt())
                .updatedAt(tenant.getUpdatedAt())
                .build();
    }

    @Override
    public TenantResponse getTenantDetail(Long id) {
        log.info("查询租户详情，ID: {}", id);

        Tenant tenant = tenantMapper.selectById(id);
        if (tenant == null) {
            log.warn("租户不存在，ID: {}", id);
            throw new BusinessException(ErrorCode.TENANT_NOT_FOUND);
        }

        return buildTenantResponse(tenant);
    }

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

}
