package com.sino.mci.admin.service;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sino.mci.admin.dto.CreateTenantRequest;
import com.sino.mci.admin.dto.CreateUserRequest;
import com.sino.mci.admin.dto.LoginResponse;
import com.sino.mci.admin.dto.PlatformUserResponse;
import com.sino.mci.admin.dto.TokenResponse;
import com.sino.mci.admin.dto.UpdateTenantRequest;
import com.sino.mci.admin.dto.UpdateUserRequest;
import com.sino.mci.admin.dto.UserResponse;
import com.sino.mci.admin.entity.PlatformRole;
import com.sino.mci.admin.entity.PlatformUser;
import com.sino.mci.admin.entity.Tenant;
import com.sino.mci.admin.entity.UserRole;
import com.sino.mci.admin.repository.PlatformRoleMapper;
import com.sino.mci.admin.repository.PlatformUserMapper;
import com.sino.mci.admin.repository.TenantMapper;
import com.sino.mci.admin.repository.UserRoleMapper;
import com.sino.mci.admin.security.AuthContext;
import com.sino.mci.exception.BusinessException;
import com.sino.mci.exception.UnauthorizedException;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class AccountService {

    private static final String TENANT_ADMIN_ROLE_CODE = "tenant_admin";
    private static final String PLATFORM_ADMIN_ROLE_CODE = "platform_admin";
    private static final String SYSTEM_TENANT_CODE = "system";
    private static final String GLOBAL_ADMIN_USERNAME = "superadmin";

    private final TenantMapper tenantMapper;
    private final PlatformUserMapper userMapper;
    private final PlatformRoleMapper roleMapper;
    private final UserRoleMapper userRoleMapper;

    @Transactional
    public Tenant createTenant(CreateTenantRequest request) {
        Tenant existing = tenantMapper.selectOne(
                new LambdaQueryWrapper<Tenant>().eq(Tenant::getTenantCode, request.getTenantCode()));
        if (existing != null) {
            throw new BusinessException("租户编码已存在: " + request.getTenantCode());
        }

        Tenant tenant = new Tenant();
        tenant.setTenantCode(request.getTenantCode());
        tenant.setTenantName(request.getTenantName());
        tenant.setInboundWebhookUrl(request.getInboundWebhookUrl());
        tenant.setStatus(1);
        tenantMapper.insert(tenant);

        if (StringUtils.hasText(request.getInitAdminUsername()) && StringUtils.hasText(request.getInitAdminPassword())) {
            createUserInternal(tenant.getTenantCode(), request.getInitAdminUsername(), request.getInitAdminPassword(),
                    request.getInitAdminUsername(), null, List.of(TENANT_ADMIN_ROLE_CODE));
        }

        return tenant;
    }

    @Transactional
    public Tenant updateTenant(Long id, UpdateTenantRequest request) {
        Tenant tenant = tenantMapper.selectById(id);
        if (tenant == null) {
            throw new BusinessException("租户不存在: " + id);
        }
        tenant.setTenantName(request.getTenantName());
        tenant.setInboundWebhookUrl(request.getInboundWebhookUrl());
        if (request.getStatus() != null) {
            tenant.setStatus(request.getStatus());
        }
        tenantMapper.updateById(tenant);
        return tenant;
    }

    @Transactional
    public void deleteTenant(Long id) {
        Tenant tenant = tenantMapper.selectById(id);
        if (tenant == null) {
            throw new BusinessException("租户不存在: " + id);
        }
        if (SYSTEM_TENANT_CODE.equals(tenant.getTenantCode())) {
            throw new BusinessException("不能删除系统默认租户");
        }
        tenantMapper.deleteById(id);
    }

    @Transactional
    public UserResponse createUser(String tenantCode, CreateUserRequest request) {
        PlatformUser user = createUserInternal(tenantCode, request.getUsername(), request.getPassword(),
                request.getRealName(), request.getPhone(), request.getRoleCodes());
        return toUserResponse(user);
    }

    private PlatformUser createUserInternal(String tenantCode, String username, String password,
                                            String realName, String phone, List<String> roleCodes) {
        Tenant tenant = tenantMapper.selectOne(
                new LambdaQueryWrapper<Tenant>().eq(Tenant::getTenantCode, tenantCode));
        if (tenant == null) {
            throw new BusinessException("租户不存在: " + tenantCode);
        }

        PlatformUser existing = userMapper.selectOne(
                new LambdaQueryWrapper<PlatformUser>()
                        .eq(PlatformUser::getTenantCode, tenantCode)
                        .eq(PlatformUser::getUsername, username));
        if (existing != null) {
            throw new BusinessException("用户名已存在: " + username);
        }

        PlatformUser user = new PlatformUser();
        user.setTenantCode(tenantCode);
        user.setUsername(username);
        user.setPassword(BCrypt.hashpw(password, BCrypt.gensalt()));
        user.setRealName(realName);
        user.setPhone(phone);
        user.setStatus(1);
        userMapper.insert(user);

        bindUserRoles(user.getId(), roleCodes);
        return user;
    }

    @Transactional
    public UserResponse updateUser(Long id, UpdateUserRequest request) {
        PlatformUser user = userMapper.selectById(id);
        if (user == null) {
            throw new BusinessException("用户不存在: " + id);
        }
        user.setRealName(request.getRealName());
        user.setPhone(request.getPhone());
        if (request.getStatus() != null) {
            user.setStatus(request.getStatus());
        }
        userMapper.updateById(user);

        bindUserRoles(user.getId(), request.getRoleCodes());
        return toUserResponse(user);
    }

    @Transactional
    public void deleteUser(Long id) {
        PlatformUser user = userMapper.selectById(id);
        if (user == null) {
            throw new BusinessException("用户不存在: " + id);
        }
        if (SYSTEM_TENANT_CODE.equals(user.getTenantCode()) && GLOBAL_ADMIN_USERNAME.equals(user.getUsername())) {
            throw new BusinessException("不能删除全局管理员");
        }
        AuthContext.AuthUser current = AuthContext.get();
        if (current != null && Objects.equals(current.getUserId(), user.getId())) {
            throw new BusinessException("不能删除当前登录用户");
        }
        userMapper.deleteById(id);
    }

    public TokenResponse login(String tenantCode, String username, String password) {
        PlatformUser user = userMapper.selectOne(
                new LambdaQueryWrapper<PlatformUser>()
                        .eq(PlatformUser::getTenantCode, tenantCode)
                        .eq(PlatformUser::getUsername, username)
                        .eq(PlatformUser::getStatus, 1));
        if (user == null || !BCrypt.checkpw(password, user.getPassword())) {
            throw new UnauthorizedException("用户名或密码错误");
        }

        LoginResponse userInfo = new LoginResponse();
        userInfo.setId(user.getId());
        userInfo.setTenantCode(user.getTenantCode());
        userInfo.setUsername(user.getUsername());
        userInfo.setRealName(user.getRealName());
        userInfo.setPhone(user.getPhone());
        userInfo.setRoleCodes(loadRoleCodes(user.getId()));

        StpUtil.login(user.getId());
        StpUtil.getSession().set("tenantCode", user.getTenantCode());
        StpUtil.getSession().set("username", user.getUsername());
        StpUtil.getSession().set("roleCodes", userInfo.getRoleCodes());

        return new TokenResponse(StpUtil.getTokenValue(), userInfo);
    }

    public List<Tenant> listTenants() {
        return tenantMapper.selectList(null);
    }

    public List<PlatformRole> listRoles() {
        return roleMapper.selectList(null);
    }

    public List<PlatformUserResponse> listUsers(String tenantCode) {
        LambdaQueryWrapper<PlatformUser> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(tenantCode)) {
            wrapper.eq(PlatformUser::getTenantCode, tenantCode);
        } else if (!isPlatformAdmin()) {
            String currentTenant = AuthContext.currentTenantCode();
            if (currentTenant != null) {
                wrapper.eq(PlatformUser::getTenantCode, currentTenant);
            }
        }
        List<PlatformUser> users = userMapper.selectList(wrapper);
        return users.stream().map(this::toPlatformUserResponse).collect(Collectors.toList());
    }

    private boolean isPlatformAdmin() {
        AuthContext.AuthUser current = AuthContext.get();
        return current != null && current.getRoleCodes() != null
                && current.getRoleCodes().contains(PLATFORM_ADMIN_ROLE_CODE);
    }

    private void bindUserRoles(Long userId, List<String> roleCodes) {
        if (CollectionUtils.isEmpty(roleCodes)) {
            return;
        }
        userRoleMapper.delete(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userId));
        for (String roleCode : roleCodes) {
            PlatformRole role = roleMapper.selectOne(
                    new LambdaQueryWrapper<PlatformRole>().eq(PlatformRole::getRoleCode, roleCode));
            if (role == null) {
                throw new BusinessException("角色不存在: " + roleCode);
            }
            UserRole userRole = new UserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(role.getId());
            userRoleMapper.insert(userRole);
        }
    }

    private UserResponse toUserResponse(PlatformUser user) {
        UserResponse response = new UserResponse();
        response.setId(user.getId());
        response.setTenantCode(user.getTenantCode());
        response.setUsername(user.getUsername());
        response.setRealName(user.getRealName());
        response.setPhone(user.getPhone());
        response.setEmail(user.getEmail());
        response.setStatus(user.getStatus());
        response.setRoleCodes(loadRoleCodes(user.getId()));
        response.setCreateTime(user.getCreateTime());
        response.setUpdateTime(user.getUpdateTime());
        return response;
    }

    private PlatformUserResponse toPlatformUserResponse(PlatformUser user) {
        PlatformUserResponse response = new PlatformUserResponse();
        response.setId(user.getId());
        response.setTenantCode(user.getTenantCode());
        response.setUsername(user.getUsername());
        response.setRealName(user.getRealName());
        response.setPhone(user.getPhone());
        response.setStatus(user.getStatus());
        response.setRoleCodes(loadRoleCodes(user.getId()));
        response.setCreateTime(user.getCreateTime());
        return response;
    }

    private List<String> loadRoleCodes(Long userId) {
        return userRoleMapper.selectList(
                        new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userId))
                .stream()
                .map(UserRole::getRoleId)
                .distinct()
                .map(roleMapper::selectById)
                .filter(role -> role != null)
                .map(PlatformRole::getRoleCode)
                .collect(Collectors.toList());
    }
}
