package com.lesingle.modules.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lesingle.common.constants.BaseEntityConstants;
import com.lesingle.common.constants.RoleConstants;
import com.lesingle.common.constants.TenantConstants;
import com.lesingle.common.enums.CommonStatus;
import com.lesingle.common.enums.ErrorCode;
import com.lesingle.common.enums.TenantType;
import com.lesingle.common.enums.UserSource;
import com.lesingle.common.enums.UserType;
import com.lesingle.common.exception.BusinessException;
import com.lesingle.common.result.PageResult;
import com.lesingle.modules.sys.dto.CreateTenantDto;
import com.lesingle.modules.sys.dto.UpdateTenantDto;
import com.lesingle.modules.sys.entity.*;
import com.lesingle.modules.sys.mapper.*;
import com.lesingle.modules.sys.service.ISysTenantService;
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 java.util.*;

/**
 * 内部租户编码，列表查询时隐藏
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements ISysTenantService {

    /** 广东省图租户编码，作为新租户权限模板 */
    private static final String TEMPLATE_TENANT_CODE = "gdlib";

    /** 基础管理权限（模板租户可能缺少，需补充） */
    private static final List<String[]> BASE_ADMIN_PERMISSIONS = List.of(
            // {name, code, resource, action, description}
            new String[]{"更新用户", "user:update", "user", "update", "允许更新用户信息"},
            new String[]{"删除用户", "user:delete", "user", "delete", "允许删除用户"},
            new String[]{"创建角色", "role:create", "role", "create", "允许创建新角色"},
            new String[]{"更新角色", "role:update", "role", "update", "允许更新角色信息"},
            new String[]{"删除角色", "role:delete", "role", "delete", "允许删除角色"},
            new String[]{"分配角色", "role:assign", "role", "assign", "允许给用户分配角色"},
            new String[]{"查看权限", "permission:read", "permission", "read", "允许查看权限列表"}
    );

    private final SysUserMapper userMapper;
    private final SysRoleMapper roleMapper;
    private final SysPermissionMapper permissionMapper;
    private final SysRolePermissionMapper rolePermissionMapper;
    private final SysUserRoleMapper userRoleMapper;
    private final SysTenantMenuMapper tenantMenuMapper;
    private final PasswordEncoder passwordEncoder;

    @Override
    @Transactional
    public Map<String, Object> createTenant(CreateTenantDto dto, Long currentTenantId) {
        log.info("开始创建租户，编码：{}", dto.getCode());
        checkSuperTenant(currentTenantId);

        // 验证编码唯一
        if (getOne(new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getCode, dto.getCode()), false) != null) {
            throw BusinessException.of(ErrorCode.CONFLICT, "租户编码已存在");
        }

        // 1. 创建租户
        SysTenant tenant = new SysTenant();
        tenant.setName(dto.getName());
        tenant.setCode(dto.getCode());
        tenant.setDomain(dto.getDomain());
        tenant.setDescription(dto.getDescription());
        tenant.setTenantType(dto.getTenantType() != null ? dto.getTenantType() : TenantType.OTHER.getValue());
        tenant.setIsSuper(0);
        save(tenant);
        Long tenantId = tenant.getId();

        // 2. 复制模板租户权限 + 补充基础管理权限
        List<Long> permissionIds = copyTemplatePermissions(tenantId);

        // 3. 创建管理员角色
        SysRole adminRole = new SysRole();
        adminRole.setTenantId(tenantId);
        adminRole.setName("机构管理员");
        adminRole.setCode(RoleConstants.TENANT_ADMIN);
        adminRole.setDescription(tenant.getName() + "管理员角色，拥有该租户所有权限");
        roleMapper.insert(adminRole);

        // 4. 绑定角色-权限
        for (Long permId : permissionIds) {
            SysRolePermission rp = new SysRolePermission();
            rp.setRoleId(adminRole.getId());
            rp.setPermissionId(permId);
            rolePermissionMapper.insert(rp);
        }

        // 5. 创建管理员用户
        String adminUsername = dto.getAdminUsername() != null && !dto.getAdminUsername().isBlank()
                ? dto.getAdminUsername() : "admin";
        String adminPassword = dto.getAdminPassword() != null && !dto.getAdminPassword().isBlank()
                ? dto.getAdminPassword() : "admin@" + dto.getCode();

        SysUser adminUser = new SysUser();
        adminUser.setTenantId(tenantId);
        adminUser.setUsername(adminUsername);
        adminUser.setPassword(passwordEncoder.encode(adminPassword));
        adminUser.setNickname(tenant.getName() + "管理员");
        adminUser.setStatus(CommonStatus.ENABLED.getValue());
        adminUser.setUserSource(UserSource.ADMIN_CREATED.getValue());
        adminUser.setUserType(UserType.ADULT.getValue());
        userMapper.insert(adminUser);

        // 6. 绑定用户-角色
        SysUserRole ur = new SysUserRole();
        ur.setUserId(adminUser.getId());
        ur.setRoleId(adminRole.getId());
        userRoleMapper.insert(ur);

        // 7. 分配菜单
        if (dto.getMenuIds() != null && !dto.getMenuIds().isEmpty()) {
            for (Long menuId : dto.getMenuIds()) {
                SysTenantMenu tm = new SysTenantMenu();
                tm.setTenantId(tenantId);
                tm.setMenuId(menuId);
                tenantMenuMapper.insert(tm);
            }
        }

        log.info("租户创建成功，ID：{}，管理员：{}", tenantId, adminUsername);

        // 返回租户信息 + 管理员凭据
        Map<String, Object> result = new HashMap<>();
        result.put("tenant", tenant);
        result.put("admin", Map.of(
                "username", adminUsername,
                "password", adminPassword,
                "userId", adminUser.getId(),
                "nickname", adminUser.getNickname()
        ));
        return result;
    }

    /**
     * 从模板租户复制权限，并补充基础管理权限
     */
    private List<Long> copyTemplatePermissions(Long newTenantId) {
        List<Long> newPermissionIds = new ArrayList<>();

        // 查找模板租户
        SysTenant templateTenant = getOne(
                new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getCode, TEMPLATE_TENANT_CODE), false);
        if (templateTenant == null) {
            log.warn("模板租户 {} 不存在，仅创建基础管理权限", TEMPLATE_TENANT_CODE);
        } else {
            // 复制模板租户的所有权限
            List<SysPermission> templatePerms = permissionMapper.selectList(
                    new LambdaQueryWrapper<SysPermission>()
                            .eq(SysPermission::getTenantId, templateTenant.getId())
                            .eq(SysPermission::getValidState, BaseEntityConstants.VALID));
            for (SysPermission tp : templatePerms) {
                SysPermission np = new SysPermission();
                np.setTenantId(newTenantId);
                np.setName(tp.getName());
                np.setCode(tp.getCode());
                np.setResource(tp.getResource());
                np.setAction(tp.getAction());
                np.setDescription(tp.getDescription());
                permissionMapper.insert(np);
                newPermissionIds.add(np.getId());
            }
        }

        // 收集已有的权限编码，避免重复
        Set<String> existingCodes = new HashSet<>();
        for (Long pid : newPermissionIds) {
            SysPermission p = permissionMapper.selectById(pid);
            if (p != null) existingCodes.add(p.getCode());
        }

        // 补充基础管理权限
        for (String[] perm : BASE_ADMIN_PERMISSIONS) {
            if (!existingCodes.contains(perm[1])) {
                SysPermission np = new SysPermission();
                np.setTenantId(newTenantId);
                np.setName(perm[0]);
                np.setCode(perm[1]);
                np.setResource(perm[2]);
                np.setAction(perm[3]);
                np.setDescription(perm[4]);
                permissionMapper.insert(np);
                newPermissionIds.add(np.getId());
            }
        }

        return newPermissionIds;
    }

    @Override
    public PageResult<Map<String, Object>> findAll(Long page, Long pageSize, String keyword, String tenantType) {
        LambdaQueryWrapper<SysTenant> wrapper = new LambdaQueryWrapper<SysTenant>()
                .eq(SysTenant::getValidState, BaseEntityConstants.VALID)
                .notIn(SysTenant::getCode, TenantConstants.INTERNAL_TENANT_CODES)
                .orderByDesc(SysTenant::getCreateTime);

        if (keyword != null && !keyword.isBlank()) {
            wrapper.and(w -> w.like(SysTenant::getName, keyword).or().like(SysTenant::getCode, keyword));
        }
        if (tenantType != null && !tenantType.isBlank()) {
            wrapper.eq(SysTenant::getTenantType, tenantType);
        }

        IPage<SysTenant> result = baseMapper.selectPage(new Page<>(page, pageSize), wrapper);

        // 为每个租户附加用户数
        List<Map<String, Object>> list = new ArrayList<>();
        for (SysTenant tenant : result.getRecords()) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", tenant.getId());
            map.put("name", tenant.getName());
            map.put("code", tenant.getCode());
            map.put("domain", tenant.getDomain());
            map.put("description", tenant.getDescription());
            map.put("isSuper", tenant.getIsSuper());
            map.put("tenantType", tenant.getTenantType());
            map.put("validState", tenant.getValidState());
            map.put("createTime", tenant.getCreateTime());

            Long userCount = userMapper.selectCount(
                    new LambdaQueryWrapper<SysUser>().eq(SysUser::getTenantId, tenant.getId()).eq(SysUser::getValidState, BaseEntityConstants.VALID));
            map.put("_count", Map.of("users", userCount));

            list.add(map);
        }

        return new PageResult<>(list, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public Map<String, Object> findDetail(Long id) {
        SysTenant tenant = getById(id);
        if (tenant == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "租户不存在");
        }

        Map<String, Object> map = new HashMap<>();
        map.put("id", tenant.getId());
        map.put("name", tenant.getName());
        map.put("code", tenant.getCode());
        map.put("domain", tenant.getDomain());
        map.put("description", tenant.getDescription());
        map.put("isSuper", tenant.getIsSuper());
        map.put("tenantType", tenant.getTenantType());
        map.put("validState", tenant.getValidState());
        map.put("createTime", tenant.getCreateTime());

        Long userCount = userMapper.selectCount(
                new LambdaQueryWrapper<SysUser>().eq(SysUser::getTenantId, id).eq(SysUser::getValidState, BaseEntityConstants.VALID));
        map.put("_count", Map.of("users", userCount));

        return map;
    }

    @Override
    public SysTenant updateTenant(Long id, UpdateTenantDto dto, Long currentTenantId) {
        log.info("开始更新租户，ID：{}", id);
        checkSuperTenant(currentTenantId);

        SysTenant existing = getById(id);
        if (existing == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "租户不存在");
        }

        SysTenant tenant = new SysTenant();
        tenant.setId(id);
        if (dto.getName() != null) tenant.setName(dto.getName());
        if (dto.getCode() != null) tenant.setCode(dto.getCode());
        if (dto.getDomain() != null) tenant.setDomain(dto.getDomain());
        if (dto.getDescription() != null) tenant.setDescription(dto.getDescription());
        if (dto.getTenantType() != null) tenant.setTenantType(dto.getTenantType());
        updateById(tenant);

        // 更新菜单关联（先删后增）
        if (dto.getMenuIds() != null) {
            tenantMenuMapper.delete(
                    new LambdaQueryWrapper<SysTenantMenu>().eq(SysTenantMenu::getTenantId, id));
            for (Long menuId : dto.getMenuIds()) {
                SysTenantMenu tm = new SysTenantMenu();
                tm.setTenantId(id);
                tm.setMenuId(menuId);
                tenantMenuMapper.insert(tm);
            }
        }

        return getById(id);
    }

    @Override
    public void toggleStatus(Long id, Long currentTenantId) {
        log.info("切换租户状态，ID：{}", id);
        checkSuperTenant(currentTenantId);

        SysTenant tenant = getById(id);
        if (tenant == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "租户不存在");
        }
        if (tenant.getIsSuper() == 1) {
            throw BusinessException.of(ErrorCode.FORBIDDEN, "不能修改超级租户状态");
        }

        SysTenant update = new SysTenant();
        update.setId(id);
        update.setValidState(tenant.getValidState() == BaseEntityConstants.VALID ? BaseEntityConstants.INVALID : BaseEntityConstants.VALID);
        updateById(update);
    }

    @Override
    public void removeTenant(Long id, Long currentTenantId) {
        log.info("删除租户，ID：{}", id);
        checkSuperTenant(currentTenantId);

        SysTenant tenant = getById(id);
        if (tenant == null) {
            throw BusinessException.of(ErrorCode.NOT_FOUND, "租户不存在");
        }
        if (tenant.getIsSuper() == 1) {
            throw BusinessException.of(ErrorCode.FORBIDDEN, "不能删除超级租户");
        }
        removeById(id);
    }

    @Override
    public SysTenant getMyTenant(Long tenantId) {
        return getById(tenantId);
    }

    @Override
    public void updateMyTenant(Long tenantId, String name, String description) {
        SysTenant tenant = new SysTenant();
        tenant.setId(tenantId);
        if (name != null) tenant.setName(name);
        if (description != null) tenant.setDescription(description);
        updateById(tenant);
    }

    @Override
    public boolean isSuperTenant(Long tenantId) {
        if (tenantId == null) return false;
        SysTenant tenant = getById(tenantId);
        return tenant != null && tenant.getIsSuper() == 1;
    }

    private void checkSuperTenant(Long tenantId) {
        if (!isSuperTenant(tenantId)) {
            throw BusinessException.of(ErrorCode.FORBIDDEN, "仅超级租户可执行此操作");
        }
    }
}
