package com.ga.api.service.system;

import com.ga.common.exception.BizException;
import com.ga.common.exception.ErrorCode;
import com.ga.common.model.PageResponse;
import com.ga.common.system.SystemConfigService;
import com.ga.core.mapper.user.UserMapper;
import com.ga.core.mapstruct.UserMapStruct;
import com.ga.core.vo.user.UserResp;
import com.ga.core.vo.user.UserSaveReq;
import com.ga.core.vo.user.UserSearchParam;
import com.ga.core.vo.user.UserStatus;
import com.ga.core.vo.user.UserVO;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserMapper mapper;
    private final PasswordEncoder passwordEncoder;
    private final SystemConfigService configService;
    private final UserMapStruct userMapStruct;

    @Transactional(readOnly = true)
    public PageResponse<UserResp> list(UserSearchParam param) {
        param.startPage();
        return PageResponse.of(mapper.selectList(param));
    }

    @Transactional(readOnly = true)
    public UserResp detail(Long userId) {
        UserResp r = mapper.selectDetailById(userId);
        if (r == null) throw new BizException(ErrorCode.NOT_FOUND);
        r.setRoleCodes(mapper.selectRoleCodes(userId));
        return r;
    }

    @Transactional
    public Long create(UserSaveReq req) {
        if (mapper.selectByLoginId(req.getLoginId()) != null) {
            throw new BizException(ErrorCode.DUPLICATE_DATA, "이미 사용 중인 로그인 ID입니다");
        }
        String initialPwd = req.getPassword();
        if (initialPwd == null || initialPwd.isBlank()) {
            initialPwd = "init1234!";  // 임시 — 로그인 후 변경 강제
        }
        UserVO vo = userMapStruct.toVO(req);
        vo.setPassword(passwordEncoder.encode(initialPwd));
        vo.setStatus(req.getStatus() != null ? req.getStatus() : UserStatus.ACTIVE.name());
        mapper.insert(vo);

        if (req.getRoleIds() != null) {
            req.getRoleIds().forEach(rid -> mapper.insertUserRole(vo.getUserId(), rid));
        }
        return vo.getUserId();
    }

    @Transactional
    public void update(Long userId, UserSaveReq req) {
        UserVO vo = mapper.selectById(userId);
        if (vo == null) throw new BizException(ErrorCode.NOT_FOUND);
        userMapStruct.updateVO(req, vo);
        vo.setUserId(userId);
        mapper.update(vo);

        if (req.getRoleIds() != null) {
            mapper.deleteUserRoles(userId);
            req.getRoleIds().forEach(rid -> mapper.insertUserRole(userId, rid));
        }
    }

    @Transactional
    public void resetPassword(Long userId) {
        int min = configService.getInt("PASSWORD_MIN_LEN", 8);
        String temp = "reset" + System.currentTimeMillis() % 1_000_000;
        if (temp.length() < min) temp = temp + "!@#";
        mapper.updatePassword(userId, passwordEncoder.encode(temp));
    }

    @Transactional
    public void unlock(Long userId) {
        mapper.resetFailCount(userId);
        mapper.updateStatus(userId, UserStatus.ACTIVE.name());
    }

    @Transactional
    public void updatePhone(Long userId, String phone) {
        if (mapper.selectById(userId) == null) {
            throw new BizException(ErrorCode.NOT_FOUND);
        }
        String trimmed = phone == null || phone.isBlank() ? null : phone.trim();
        mapper.updatePhone(userId, trimmed);
    }

    @Transactional(readOnly = true)
    public List<String> roleCodes(Long userId) {
        return mapper.selectRoleCodes(userId);
    }
}
