package com.yaoai.security.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.yaoai.common.exception.BizException;
import com.yaoai.common.exception.ErrorCode;
import com.yaoai.domain.entity.Tenant;
import com.yaoai.domain.entity.TenantMember;
import com.yaoai.domain.entity.User;
import com.yaoai.domain.mapper.TenantMapper;
import com.yaoai.domain.mapper.TenantMemberMapper;
import com.yaoai.domain.mapper.UserMapper;
import com.yaoai.security.dto.LoginRequest;
import com.yaoai.security.dto.LoginResponse;
import com.yaoai.security.dto.RegisterRequest;
import com.yaoai.security.dto.UserInfo;
import com.yaoai.security.service.AuthService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;

@Slf4j
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService {

    private final UserMapper userMapper;
    private final TenantMapper tenantMapper;
    private final TenantMemberMapper tenantMemberMapper;

    @Override
    @Transactional
    public LoginResponse register(RegisterRequest req) {
        if (userMapper.existsByEmail(req.getEmail())) {
            throw new BizException(ErrorCode.INVALID_PARAM, "该邮箱已被注册");
        }

        // 创建租户
        Tenant tenant = new Tenant();
        tenant.setName(req.getTenantName() != null ? req.getTenantName() : req.getUsername() + " 的空间");
        tenant.setSlug(buildSlug(req.getUsername()));
        tenant.setPlan("free");
        tenant.setStatus(1);
        tenant.setCredits(BigDecimal.ZERO);
        tenant.setFrozenCredits(BigDecimal.ZERO);
        tenantMapper.insert(tenant);

        // 创建用户
        User user = new User();
        user.setTenantId(tenant.getId());
        user.setUsername(req.getUsername());
        user.setEmail(req.getEmail());
        user.setPasswordHash(BCrypt.hashpw(req.getPassword(), BCrypt.gensalt()));
        user.setRole("admin");
        user.setStatus(1);
        userMapper.insert(user);

        // 建立租户成员关系
        TenantMember member = new TenantMember();
        member.setTenantId(tenant.getId());
        member.setUserId(user.getId());
        member.setRole("owner");
        tenantMemberMapper.insert(member);

        return buildLoginResponse(user);
    }

    @Override
    public LoginResponse login(LoginRequest req) {
        User user = userMapper.findActiveByEmail(req.getEmail())
                .orElseThrow(() -> new BizException(ErrorCode.INVALID_PARAM, "邮箱或密码错误"));

        if (!BCrypt.checkpw(req.getPassword(), user.getPasswordHash())) {
            throw new BizException(ErrorCode.INVALID_PARAM, "邮箱或密码错误");
        }

        // 更新最后登录时间（异步写不影响响应）
        User update = new User();
        update.setId(user.getId());
        update.setLastLoginAt(LocalDateTime.now());
        userMapper.updateById(update);

        return buildLoginResponse(user);
    }

    @Override
    public void logout() {
        StpUtil.logout();
    }

    @Override
    public UserInfo me() {
        Long userId = StpUtil.getLoginIdAsLong();
        User user = userMapper.selectById(userId);
        if (user == null || user.getDeletedAt() != null) {
            throw new BizException(ErrorCode.INVALID_PARAM, "用户不存在");
        }
        return toUserInfo(user);
    }

    // ---- private helpers ----

    private LoginResponse buildLoginResponse(User user) {
        StpUtil.login(user.getId());
        // 将 tenantId 存入 Session，避免后续每次请求都查库
        StpUtil.getSession().set("tenantId", user.getTenantId());

        LoginResponse resp = new LoginResponse();
        resp.setToken(StpUtil.getTokenValue());
        resp.setUser(toUserInfo(user));
        return resp;
    }

    private UserInfo toUserInfo(User user) {
        UserInfo info = new UserInfo();
        info.setId(user.getId());
        info.setTenantId(user.getTenantId());
        info.setUsername(user.getUsername());
        info.setEmail(user.getEmail());
        info.setRole(user.getRole());
        info.setAvatarUrl(user.getAvatarUrl());
        return info;
    }

    private String buildSlug(String username) {
        String base = username.toLowerCase().replaceAll("[^a-z0-9-]", "-");
        return base + "-" + RandomUtil.randomString(4);
    }
}
