package top.tqx.demo_1.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.tqx.demo_1.constant.CommonConstant;
import top.tqx.demo_1.dto.DepartmentCreateRequest;
import top.tqx.demo_1.dto.DepartmentUpdateRequest;
import top.tqx.demo_1.entity.Department;
import top.tqx.demo_1.entity.User;
import top.tqx.demo_1.enums.DeptTypeEnum;
import top.tqx.demo_1.mapper.DepartmentMapper;
import top.tqx.demo_1.mapper.UserMapper;
import top.tqx.demo_1.service.DepartmentService;
import top.tqx.demo_1.vo.DepartmentVO;
import top.tqx.demo_1.vo.UserVO;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements DepartmentService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public List<DepartmentVO> listDepartments() {
        LambdaQueryWrapper<Department> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Department::getStatus, CommonConstant.STATUS_ENABLE);
        wrapper.orderByAsc(Department::getDeptLevel, Department::getId);
        
        List<Department> departments = this.list(wrapper);
        return departments.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createDepartment(DepartmentCreateRequest request) {
        if (request.getDeptType() == null || request.getDeptType().isEmpty()) {
            throw new RuntimeException("部门类型不能为空");
        }
        
        DeptTypeEnum deptType = DeptTypeEnum.getByCode(request.getDeptType());
        if (deptType == null) {
            throw new RuntimeException("部门类型无效");
        }
        
        validateDepartmentHierarchy(request.getParentId(), deptType);
        
        LambdaQueryWrapper<Department> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Department::getDeptName, request.getDeptName());
        wrapper.eq(Department::getParentId, request.getParentId() != null ? request.getParentId() : 0);
        if (this.count(wrapper) > 0) {
            throw new RuntimeException("同级部门名称已存在");
        }
        
        Department department = new Department();
        BeanUtils.copyProperties(request, department);
        department.setStatus(CommonConstant.STATUS_ENABLE);
        department.setCreateTime(LocalDateTime.now());
        
        if (request.getParentId() != null && request.getParentId() > 0) {
            Department parent = this.getById(request.getParentId());
            if (parent != null) {
                department.setDeptLevel(parent.getDeptLevel() + 1);
            }
        } else {
            department.setDeptLevel(deptType.getLevel());
        }
        
        this.save(department);
    }
    
    private void validateDepartmentHierarchy(Long parentId, DeptTypeEnum deptType) {
        if (deptType == DeptTypeEnum.HEADQUARTERS) {
            if (parentId != null && parentId > 0) {
                throw new RuntimeException("总公司必须是顶级部门");
            }
        } else if (deptType == DeptTypeEnum.BRANCH) {
            if (parentId == null || parentId <= 0) {
                throw new RuntimeException("分公司必须隶属于总公司");
            }
            Department parent = this.getById(parentId);
            if (parent == null) {
                throw new RuntimeException("父部门不存在");
            }
            if (!DeptTypeEnum.HEADQUARTERS.getCode().equals(parent.getDeptType())) {
                throw new RuntimeException("分公司只能隶属于总公司");
            }
        } else if (deptType == DeptTypeEnum.DEPARTMENT) {
            if (parentId == null || parentId <= 0) {
                throw new RuntimeException("部门必须隶属于分公司");
            }
            Department parent = this.getById(parentId);
            if (parent == null) {
                throw new RuntimeException("父部门不存在");
            }
            if (!DeptTypeEnum.BRANCH.getCode().equals(parent.getDeptType())) {
                throw new RuntimeException("部门只能隶属于分公司");
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDepartment(Long id, DepartmentUpdateRequest request) {
        Department department = this.getById(id);
        if (department == null) {
            throw new RuntimeException("部门不存在");
        }
        
        BeanUtils.copyProperties(request, department, "createTime", "deptLevel");
        this.updateById(department);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDepartment(Long id) {
        Department department = this.getById(id);
        if (department == null) {
            throw new RuntimeException("部门不存在");
        }
        
        if (DeptTypeEnum.HEADQUARTERS.getCode().equals(department.getDeptType())) {
            throw new RuntimeException("总公司不可删除");
        }
        
        LambdaQueryWrapper<Department> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Department::getParentId, id);
        long count = this.count(wrapper);
        if (count > 0) {
            throw new RuntimeException("该部门下存在子部门，无法删除");
        }
        
        this.removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void setDepartmentManager(Long id, Long managerId) {
        Department department = this.getById(id);
        if (department == null) {
            throw new RuntimeException("部门不存在");
        }
        
        department.setManagerId(managerId);
        this.updateById(department);
    }

    @Override
    public List<UserVO> getDepartmentUsers(Long deptId) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getDeptId, deptId);
        wrapper.eq(User::getStatus, CommonConstant.STATUS_ENABLE);
        
        List<User> users = userMapper.selectList(wrapper);
        return users.stream()
                .map(this::convertToUserVO)
                .collect(Collectors.toList());
    }

    @Override
    public Department getDepartmentById(Long id) {
        return this.getById(id);
    }

    @Override
    public String getDepartmentFullPath(Long deptId) {
        List<Department> ancestors = getDepartmentAncestors(deptId);
        StringBuilder path = new StringBuilder();
        for (Department dept : ancestors) {
            path.append(dept.getDeptName()).append("/");
        }
        Department current = this.getById(deptId);
        if (current != null) {
            path.append(current.getDeptName());
        }
        return path.toString();
    }

    @Override
    public List<Department> getDepartmentAncestors(Long deptId) {
        List<Department> ancestors = new ArrayList<>();
        Department current = this.getById(deptId);
        while (current != null && current.getParentId() != null && current.getParentId() > 0) {
            Department parent = this.getById(current.getParentId());
            if (parent != null) {
                ancestors.add(0, parent);
                current = parent;
            } else {
                break;
            }
        }
        return ancestors;
    }

    private DepartmentVO convertToVO(Department department) {
        DepartmentVO vo = new DepartmentVO();
        BeanUtils.copyProperties(department, vo);
        
        if (department.getDeptType() != null) {
            DeptTypeEnum deptType = DeptTypeEnum.getByCode(department.getDeptType());
            if (deptType != null) {
                vo.setDeptTypeName(deptType.getName());
            }
        }
        
        if (department.getParentId() != null && department.getParentId() > 0) {
            Department parent = this.getById(department.getParentId());
            if (parent != null) {
                vo.setParentName(parent.getDeptName());
            }
        }
        
        return vo;
    }
    
    private UserVO convertToUserVO(User user) {
        UserVO vo = new UserVO();
        BeanUtils.copyProperties(user, vo);
        return vo;
    }
}
