package org.dromara.web.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.app.domain.*;
import org.dromara.app.mapper.*;
import org.dromara.app.service.IDeviceCommandService;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysSocial;
import org.dromara.system.domain.SysUserPost;
import org.dromara.system.domain.SysUserRole;
import org.dromara.system.mapper.SysSocialMapper;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.mapper.SysUserPostMapper;
import org.dromara.system.mapper.SysUserRoleMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

@RequiredArgsConstructor
@Service
public class AccountCancellationService {

    private final SysUserMapper sysUserMapper;
    private final SysUserRoleMapper sysUserRoleMapper;
    private final SysUserPostMapper sysUserPostMapper;
    private final SysSocialMapper sysSocialMapper;
    private final AppDeviceMapper appDeviceMapper;
    private final AppScheduleMapper appScheduleMapper;
    private final AppScheduleDetailMapper appScheduleDetailMapper;
    private final AppSchedulingDeviceMapper appSchedulingDeviceMapper;
    private final AppWateringLogMapper appWateringLogMapper;
    private final AccountCancelCodeService accountCancelCodeService;
    private final IDeviceCommandService deviceCommandService;

    @Transactional(rollbackFor = Exception.class)
    public void cancelCurrentAccount(String code) {
        Long userId = LoginHelper.getUserId();
        if (userId == null) {
            throw new ServiceException("用户未登录");
        }
        if (LoginHelper.isSuperAdmin(userId)) {
            throw new ServiceException("超级管理员账号不允许注销");
        }
        String username = getCurrentUsername();
        accountCancelCodeService.validate(username, code);

        List<String> deviceNos = queryUserDeviceNos(userId);
        List<Long> scheduleIds = queryUserScheduleIds(userId);

        sendInitDeviceCommands(deviceNos);
        deleteAppScheduleData(userId, scheduleIds);
        deleteAppDeviceData(userId, deviceNos);
        deleteSystemUserData(userId);
        accountCancelCodeService.delete(username);
    }

    private String getCurrentUsername() {
        String username = LoginHelper.getUsername();
        if (StringUtils.isBlank(username)) {
            throw new ServiceException("用户未登录");
        }
        return username;
    }

    private List<String> queryUserDeviceNos(Long userId) {
        return appDeviceMapper.selectList(
                Wrappers.<AppDevice>lambdaQuery()
                    .select(AppDevice::getDeviceNo)
                    .eq(AppDevice::getUserId, userId)
            ).stream()
            .map(AppDevice::getDeviceNo)
            .filter(StringUtils::isNotBlank)
            .distinct()
            .toList();
    }

    private List<Long> queryUserScheduleIds(Long userId) {
        return appScheduleMapper.selectList(
                Wrappers.<AppSchedule>lambdaQuery()
                    .select(AppSchedule::getId)
                    .eq(AppSchedule::getUserId, userId)
            ).stream()
            .map(AppSchedule::getId)
            .filter(Objects::nonNull)
            .distinct()
            .toList();
    }

    private void sendInitDeviceCommands(List<String> deviceNos) {
        for (String deviceNo : deviceNos) {
            deviceCommandService.sendInitDeviceCommand(deviceNo);
        }
    }

    private void deleteAppScheduleData(Long userId, List<Long> scheduleIds) {
        if (!scheduleIds.isEmpty()) {
            appSchedulingDeviceMapper.delete(
                Wrappers.<AppSchedulingDevice>lambdaQuery()
                    .in(AppSchedulingDevice::getScheduleId, scheduleIds)
            );
            appScheduleDetailMapper.delete(
                Wrappers.<AppScheduleDetail>lambdaQuery()
                    .in(AppScheduleDetail::getScheduleId, scheduleIds)
            );
        }
        appScheduleMapper.delete(
            Wrappers.<AppSchedule>lambdaQuery()
                .eq(AppSchedule::getUserId, userId)
        );
    }

    private void deleteAppDeviceData(Long userId, List<String> deviceNos) {
        if (!deviceNos.isEmpty()) {
            appSchedulingDeviceMapper.delete(
                Wrappers.<AppSchedulingDevice>lambdaQuery()
                    .in(AppSchedulingDevice::getDeviceNo, deviceNos)
            );
            appWateringLogMapper.delete(
                Wrappers.<AppWateringLog>lambdaQuery()
                    .in(AppWateringLog::getDeviceNo, deviceNos)
            );
        }
        appWateringLogMapper.delete(
            Wrappers.<AppWateringLog>lambdaQuery()
                .eq(AppWateringLog::getUserId, userId)
        );
        appDeviceMapper.delete(
            Wrappers.<AppDevice>lambdaQuery()
                .eq(AppDevice::getUserId, userId)
        );
    }

    private void deleteSystemUserData(Long userId) {
        sysSocialMapper.delete(
            Wrappers.<SysSocial>lambdaQuery()
                .eq(SysSocial::getUserId, userId)
        );
        sysUserRoleMapper.delete(
            Wrappers.<SysUserRole>lambdaQuery()
                .eq(SysUserRole::getUserId, userId)
        );
        sysUserPostMapper.delete(
            Wrappers.<SysUserPost>lambdaQuery()
                .eq(SysUserPost::getUserId, userId)
        );
        int rows = sysUserMapper.deleteById(userId);
        if (rows < 1) {
            throw new ServiceException("注销账号失败");
        }
    }
}
