package com.dji.sample.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dji.sample.component.oss.model.OssConfiguration;
import com.dji.sample.component.oss.service.impl.OssServiceContext;
import com.dji.sample.manage.dao.IOrgMapper;
import com.dji.sample.manage.model.dto.OrgDTO;
import com.dji.sample.manage.model.dto.OrgJoinDTO;
import com.dji.sample.manage.model.dto.WorkspaceDTO;
import com.dji.sample.manage.model.entity.OrgEntity;
import com.dji.sample.manage.model.entity.UserEntity;
import com.dji.sample.manage.model.entity.UserOrgEntity;
import com.dji.sample.manage.model.entity.WorkspaceEntity;
import com.dji.sample.manage.model.enums.RoleTypeEnum;
import com.dji.sample.manage.model.param.searchParam.OrgSearchParam;
import com.dji.sample.manage.service.IOrgService;
import com.dji.sample.manage.service.IUserService;
import com.dji.sdk.common.Pagination;
import com.dji.sdk.common.PaginationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Role;
import org.springframework.stereotype.Service;
import com.dji.sample.common.util.SecurityUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URL;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

import static com.dji.sample.common.util.SecurityUtils.*;

@Service
@Transactional
public class OrgServiceImpl extends ServiceImpl<IOrgMapper, OrgEntity> implements IOrgService {

    @Autowired
    private UserOrgServiceImpl userOrgService;


    @Autowired
    @Lazy
    private IUserService userService;

    @Autowired
    private OssServiceContext ossService;

    @Override
    public Optional<OrgDTO> getOrgByOrgId(String orgId) {
        LambdaQueryWrapper<OrgEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrgEntity::getOrgId, orgId);

        OrgEntity entity = getOne(queryWrapper);
        if (entity == null) {
            return Optional.empty();
        }

        return Optional.of(entityConvertToDto(entity));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public OrgDTO addOrg(OrgDTO orgDTO) {

        OrgEntity addOrgEntity = new OrgEntity();
        addOrgEntity.setWorkspaceId(orgDTO.getWorkspaceId());

        // 绑定码 不能重复
        String bindCode = orgDTO.getBindCode();
        if (!StringUtils.hasText(bindCode)) {
            throw new RuntimeException("bindCode can't be null");
        }
        LambdaQueryWrapper<OrgEntity> bindCodeQueryWrapper = new LambdaQueryWrapper<>();
        bindCodeQueryWrapper.eq(OrgEntity::getBindCode, bindCode);
        List<OrgEntity> bindCodeOrgList = this.list(bindCodeQueryWrapper);
        if (!CollectionUtils.isEmpty(bindCodeOrgList)) {
            throw new RuntimeException("bindCode is already exit");
        }
        addOrgEntity.setBindCode(orgDTO.getBindCode());

        // 团队编码不能重复
        if (StringUtils.hasText(orgDTO.getOrgId())) {
            LambdaQueryWrapper<OrgEntity> orgIdQueryWrapper = new LambdaQueryWrapper<>();
            orgIdQueryWrapper.eq(OrgEntity::getOrgId, orgDTO.getOrgId());
            List<OrgEntity> orgIdOrgList = this.list(orgIdQueryWrapper);
            if (!CollectionUtils.isEmpty(orgIdOrgList)) {
                throw new RuntimeException("orgId is already exit");
            }
            addOrgEntity.setOrgId(orgDTO.getOrgId());
        } else {
            addOrgEntity.setOrgId(UUID.randomUUID().toString());
        }
        addOrgEntity.setOrgName(orgDTO.getOrgName());
        addOrgEntity.setOrgDesc(orgDTO.getOrgDesc());

        addOrgEntity.setCreateTime(System.currentTimeMillis());
        addOrgEntity.setCreatorId(getUserId());
        addOrgEntity.setCreatorName(getUsername());
        addOrgEntity.setUpdateTime(System.currentTimeMillis());
        addOrgEntity.setUpdaterId(getUserId());
        addOrgEntity.setUpdaterName(getUsername());

        // 新增orgAdmin
        UserEntity orgAdmin = new UserEntity();
        orgAdmin.setWorkspaceId(orgDTO.getWorkspaceId());
        orgAdmin.setUsername(orgDTO.getAdminUserName());
        orgAdmin.setPassword(orgDTO.getAdminUserPassword());
        UserEntity saveAdmin = userService.addOrgAdminUser(orgAdmin);

        addOrgEntity.setAdminUserId(saveAdmin.getUserId());

        boolean addOrgRes = this.save(addOrgEntity);

        // 增加用户和团队的权限
        UserOrgEntity userOrgEntity = new UserOrgEntity();
        userOrgEntity.setOrgId(addOrgEntity.getOrgId());
        userOrgEntity.setUserId(saveAdmin.getUserId());
        userOrgEntity.setWorkspaceId(addOrgEntity.getWorkspaceId());
        userOrgEntity.setCreateTime(System.currentTimeMillis());
        userOrgEntity.setCreatorId(getUserId());
        userOrgEntity.setCreatorName(getUsername());
        userOrgEntity.setUpdateTime(System.currentTimeMillis());
        userOrgEntity.setUpdaterId(getUserId());
        userOrgEntity.setUpdaterName(getUsername());
        userOrgEntity.setRoleType(RoleTypeEnum.ORG_ADMIN.getVal());
        boolean userOrgSaveRes = userOrgService.save(userOrgEntity);

        OrgDTO entityConvertToDto = entityConvertToDto(addOrgEntity);
        return entityConvertToDto;
    }

    @Override
    public boolean editOrg(OrgDTO orgDTO) {

        if (orgDTO.getId() == null && !StringUtils.hasText(orgDTO.getOrgId())) {
            throw new RuntimeException("id and orgId is null");
        }
        LambdaQueryWrapper<OrgEntity> queryDbWrapper = new LambdaQueryWrapper<>();
        if (orgDTO.getId() != null) {
            queryDbWrapper.eq(OrgEntity::getId, orgDTO.getId());
        } else {
            queryDbWrapper.eq(OrgEntity::getOrgId, orgDTO.getOrgId());
        }
        OrgEntity dbOrg = this.getOne(queryDbWrapper);

        LambdaUpdateWrapper<OrgEntity> updateWrapper = new LambdaUpdateWrapper<>();
        if (orgDTO.getId() != null) {
            updateWrapper.eq(OrgEntity::getId, orgDTO.getId());
        } else {
            updateWrapper.eq(OrgEntity::getOrgId, orgDTO.getOrgId());
        }

        // 绑定码 不能重复
        String bindCode = orgDTO.getBindCode();
        if (StringUtils.hasText(bindCode)) {
            if (!bindCode.equals(orgDTO.getBindCode())) {
                // 查询
                LambdaQueryWrapper<OrgEntity> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(OrgEntity::getBindCode, bindCode);
                List<OrgEntity> bingCodeList = this.list(queryWrapper);
                if (!CollectionUtils.isEmpty(bingCodeList)) {
                    throw new RuntimeException("bindCode is already exit");
                }
            }
            updateWrapper.set(OrgEntity::getBindCode, bindCode);
        }
        // 修改 名称
        if (StringUtils.hasText(orgDTO.getOrgName())) {
            updateWrapper.set(OrgEntity::getOrgName, orgDTO.getOrgName());
        }
        // 修改 描述
        if (StringUtils.hasText(orgDTO.getOrgDesc())) {
            updateWrapper.set(OrgEntity::getOrgDesc, orgDTO.getOrgDesc());
        }
        boolean update = this.update(updateWrapper);
        return update;
    }

    @Override
    public boolean delOrg(OrgDTO orgDTO) {
        if (orgDTO.getId() == null && !StringUtils.hasText(orgDTO.getOrgId())) {
            throw new RuntimeException("id and orgId is null");
        }
        boolean remove;

        if (orgDTO.getId() != null) {
            remove  = this.removeById(orgDTO.getId());
        } else {
            LambdaQueryWrapper<OrgEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OrgEntity::getOrgId, orgDTO.getOrgId());
            remove = this.remove(wrapper);
        }

        return remove;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean applyOrg(OrgJoinDTO orgDTO) {

        // 查询绑定码是否正确
        if (!StringUtils.hasText(orgDTO.getBindCode())) {
            throw new RuntimeException("bindCode is null");
        }
        if (!StringUtils.hasText(orgDTO.getOrgDesc()) && !StringUtils.hasText(orgDTO.getOrgId())) {
            throw new RuntimeException("org info is null");
        }

        LambdaQueryWrapper<OrgEntity> orgQueryWrapper = new LambdaQueryWrapper<>();
        orgQueryWrapper.eq(OrgEntity::getWorkspaceId, getWorkspaceId());
        if (StringUtils.hasText(orgDTO.getOrgId())) {
            orgQueryWrapper.eq(OrgEntity::getOrgId, orgDTO.getOrgId());
        } else if (StringUtils.hasText(orgDTO.getOrgName())) {
            orgQueryWrapper.eq(OrgEntity::getOrgName, orgDTO.getOrgName());
        }
        orgQueryWrapper.eq(OrgEntity::getBindCode, orgDTO.getBindCode());
        OrgEntity orgEntity = this.getOne(orgQueryWrapper);
        if (orgEntity == null) {
            throw new RuntimeException("org info or bindCode is error");
        }

        String joinUserId = getUserId();
        String joinOrgId = orgEntity.getOrgId();
        Integer joinUserRoleType = RoleTypeEnum.MEMBER.getVal();

        boolean addOrgRes = userOrgService.addUserToOrg(joinUserId, joinOrgId, joinUserRoleType);

        return addOrgRes;

    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean joinOrgByAdmin(OrgJoinDTO orgDTO) {

        if (!aboveAdminRole()) {
            throw new RuntimeException("current roleType is not admin");
        }
        if (orgDTO.getJoinUserRoleType() != null) {
            if (RoleTypeEnum.find(orgDTO.getJoinUserRoleType()) == RoleTypeEnum.UNKNOWN) {
                throw new RuntimeException("org roleType is error");
            }
        }

        if (!StringUtils.hasText(orgDTO.getJoinUserId()) && !StringUtils.hasText(orgDTO.getJoinUserName())) {
            throw new RuntimeException("user info is null");
        }
        if (!StringUtils.hasText(orgDTO.getOrgId()) && !StringUtils.hasText(orgDTO.getOrgName())) {
            throw new RuntimeException("org info is null");
        }
        LambdaQueryWrapper<OrgEntity> orgQueryWrapper = new LambdaQueryWrapper<>();
        orgQueryWrapper.eq(OrgEntity::getWorkspaceId, getWorkspaceId());
        if (StringUtils.hasText(orgDTO.getOrgId())) {
            orgQueryWrapper.eq(OrgEntity::getOrgId, orgDTO.getOrgId());
        } else if (StringUtils.hasText(orgDTO.getOrgName())) {
            orgQueryWrapper.eq(OrgEntity::getOrgName, orgDTO.getOrgName());
        }
        OrgEntity orgEntity = this.getOne(orgQueryWrapper);
        if (orgEntity == null) {
            throw new RuntimeException("org info or bindCode is error");
        }

        if (aboveSysAdminRole()) {
            // 系统管理员可以增加全部组织

            // 非系统管理员权限
            if (aboveSysAdminRole(orgDTO.getJoinUserRoleType())) {
                throw new RuntimeException("org roleType is error");
            }
        } else if (aboveAdminRole()) {
            // 管理员只能增加自己当前组织
            if (!orgEntity.getOrgId().equals(getOrgId())) {
                throw new RuntimeException("admin can not select other org!");
            }
            // 非组织管理员权限
            if (aboveOrgAdminRole(orgDTO.getJoinUserRoleType())) {
                throw new RuntimeException("org roleType is error");
            }
        }
        String joinUserId;
        // 查询 用户是否存在
        if (!StringUtils.hasText(orgDTO.getJoinUserId())) {

            String joinUserName = orgDTO.getJoinUserName();
            LambdaQueryWrapper<UserEntity> userQueryWrapper = new LambdaQueryWrapper<>();
            userQueryWrapper.eq(UserEntity::getUsername, joinUserName);
            UserEntity joinUser = userService.getOne(userQueryWrapper);

            if (joinUser == null) {
                throw new RuntimeException("joinUserName is error");
            }
            joinUserId = joinUser.getUserId();
        } else {
            joinUserId = StringUtils.hasText(orgDTO.getJoinUserId()) ? orgDTO.getJoinUserId() : getUserId();
        }

        String joinOrgId = orgEntity.getOrgId();
        Integer joinUserRoleType = orgDTO.getJoinUserRoleType() != null ? orgDTO.getJoinUserRoleType() : RoleTypeEnum.MEMBER.getVal();

        boolean addOrgRes = userOrgService.addUserToOrg(joinUserId, joinOrgId, joinUserRoleType);

        return addOrgRes;
    }


    @Override
    public PaginationData<OrgDTO> getOrgPage(OrgSearchParam param, Long page, Long pageSize) {
        LambdaQueryWrapper<OrgEntity> orgQueryWrapper = new LambdaQueryWrapper<>();

        if (StringUtils.hasText(param.getOrgId())) {
            orgQueryWrapper.eq(OrgEntity::getOrgId, param.getOrgId());
        }

        if (StringUtils.hasText(param.getWorkspaceId())) {
            orgQueryWrapper.eq(OrgEntity::getWorkspaceId, param.getWorkspaceId());
        }

        // 增加查询内容
        if (StringUtils.hasText(param.getOrgDesc())) {
            orgQueryWrapper.like(OrgEntity::getOrgDesc, param.getOrgDesc());
        }

        if (aboveSysAdminRole()) {

        } else {
            // 查询相关组织
            LambdaQueryWrapper<UserOrgEntity> userOrgQueryWrapper = new LambdaQueryWrapper<>();
            userOrgQueryWrapper.eq(UserOrgEntity::getUserId, getUserId());
            // userOrgQueryWrapper.eq(UserOrgEntity::getWorkspaceId, getWorkspaceId());
            List<UserOrgEntity> userOrgEntities = userOrgService.list(userOrgQueryWrapper);

            List<String> userOrgOrgIdList = userOrgEntities.stream().map(UserOrgEntity::getOrgId).distinct().collect(Collectors.toList());
            if (CollectionUtils.isEmpty(userOrgOrgIdList)) {
                return new PaginationData<>();
            }
            orgQueryWrapper.in(OrgEntity::getOrgId, userOrgOrgIdList);
        }

        Page<OrgEntity> pagination = this.page(new Page<>(page, pageSize), orgQueryWrapper);
        List<OrgDTO> orgDTOList = pagination.getRecords().stream()
                .map(this::entityConvertToDto)
                //.peek(fleet -> {})
                .collect(Collectors.toList());
        return new PaginationData<>(orgDTOList, new Pagination(pagination.getCurrent(), pagination.getSize(), pagination.getTotal()));
    }


    @Override
    public OrgDTO getOrg(OrgSearchParam param) {
        LambdaQueryWrapper<OrgEntity> orgQueryWrapper = new LambdaQueryWrapper<>();
        orgQueryWrapper.eq(OrgEntity::getWorkspaceId, param.getWorkspaceId());

        if (StringUtils.hasText(param.getRoleUserId())) {
            // 查询 权限团队
            LambdaQueryWrapper<UserOrgEntity> userOrgQueryWrapper = new LambdaQueryWrapper<>();
            userOrgQueryWrapper.eq(UserOrgEntity::getUserId, param.getRoleUserId());
            List<UserOrgEntity> userOrgEntities = userOrgService.list(userOrgQueryWrapper);
            if (CollectionUtils.isEmpty(userOrgEntities)) {
                return OrgDTO.builder().build();
            }
            List<String> roleOrgIdList = userOrgEntities.stream().map(UserOrgEntity::getOrgId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(roleOrgIdList)) {
                return OrgDTO.builder().build();
            }
            orgQueryWrapper.in(OrgEntity::getOrgId, roleOrgIdList);
        }
        if (StringUtils.hasText(param.getOrgId())) {
            orgQueryWrapper.eq(OrgEntity::getOrgId, param.getOrgId());
        }
        if (param.getId() != null) {
            orgQueryWrapper.eq(OrgEntity::getId, param.getId());
        }
        OrgEntity orgEntity = this.getOne(orgQueryWrapper);

        OrgDTO orgDTO = this.entityConvertToDto(orgEntity);

        return orgDTO;
    }

    @Override
    public String getWorkspaceIdByOrgId(String orgId) {
        LambdaQueryWrapper<OrgEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrgEntity::getOrgId, orgId)
                .select(OrgEntity::getWorkspaceId);

        OrgEntity entity = getOne(queryWrapper);
        return entity != null ? entity.getWorkspaceId() : null;
    }

    @Override
    public boolean deleteOrg(String orgId) {
        LambdaQueryWrapper<OrgEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrgEntity::getOrgId, orgId);

        return remove(queryWrapper);
    }

    @Override
    public boolean createOrg(OrgDTO orgDTO) {
        OrgEntity entity = new OrgEntity();
        entity.setOrgId(orgDTO.getOrgId());
        entity.setOrgName(orgDTO.getOrgName());
        entity.setOrgDesc(orgDTO.getOrgDesc());
        entity.setWorkspaceId(orgDTO.getWorkspaceId());

        // 设置创建者和更新者信息
        String currentUserId = SecurityUtils.getUserId();
        String currentUserName = SecurityUtils.getUsername();

        entity.setCreatorId(currentUserId);
        entity.setCreatorName(currentUserName);
        entity.setUpdaterId(currentUserId);
        entity.setUpdaterName(currentUserName);
        entity.setBindCode(orgDTO.getBindCode());

        save(entity);

        return entity.getOrgId() != null;
    }

    @Override
    public boolean updateOrg(OrgDTO orgDTO) {
        LambdaQueryWrapper<OrgEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrgEntity::getOrgId, orgDTO.getOrgId());

        OrgEntity entity = getOne(queryWrapper);
        if (entity == null) {
            return false;
        }

        entity.setOrgName(orgDTO.getOrgName());
        entity.setOrgDesc(orgDTO.getOrgDesc());
        entity.setWorkspaceId(orgDTO.getWorkspaceId());

        // 设置更新者信息
        entity.setUpdaterId(SecurityUtils.getUserId());
        entity.setUpdaterName(SecurityUtils.getUsername());

        return updateById(entity);
    }

    @Override
    public List<OrgDTO> getAllOrgs() {
        List<OrgEntity> entities = list();
        return entities.stream()
                .map(this::entityConvertToDto)
                .collect(Collectors.toList());
    }

    private OrgDTO entityConvertToDto(OrgEntity entity) {
        if (entity == null) {
            return null;
        }
        UserEntity adminUser = null;
        if (StringUtils.hasText(entity.getAdminUserId())) {
            LambdaQueryWrapper<UserEntity> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(UserEntity::getUserId, entity.getAdminUserId());
            adminUser = userService.getOne(userWrapper);
        }

        return OrgDTO.builder()
                .id(entity.getId())
                .orgId(entity.getOrgId())
                .orgName(entity.getOrgName())
                .orgDesc(entity.getOrgDesc())
                .workspaceId(entity.getWorkspaceId())
                .createTime(Objects.nonNull(entity.getCreateTime()) ? LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getCreateTime()), ZoneId.systemDefault()) : null)
                .updateTime(Objects.nonNull(entity.getUpdateTime()) ? LocalDateTime.ofInstant(Instant.ofEpochMilli(entity.getUpdateTime()), ZoneId.systemDefault()) : null)
                .bindCode(entity.getBindCode())
                .adminUserName(adminUser != null ?  adminUser.getUsername() : null)
                .logo(entity.getLogo())
                .build();
    }


    /**
     *
     * @param file
     * @return logoUrl
     */
    @Override
    public String saveLogo(MultipartFile file) {

        String workspaceId = getWorkspaceId();
        String orgId = getOrgId();
        LambdaQueryWrapper<OrgEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrgEntity::getWorkspaceId, workspaceId);
        wrapper.eq(OrgEntity::getOrgId, orgId);
        OrgEntity orgEntity = this.getOne(wrapper);

        try {
            String filenameExtension = StringUtils.getFilenameExtension(file.getOriginalFilename());
            String objectKey = OssConfiguration.objectDirPrefix + "/" + workspaceId + "/" + orgId + "/logos/" + UUID.randomUUID().toString().substring(0, 10) + "." + filenameExtension;

            ossService.putObject(OssConfiguration.bucket, objectKey, file.getInputStream());

            LambdaUpdateWrapper<OrgEntity> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(OrgEntity::getWorkspaceId, workspaceId);
            updateWrapper.eq(OrgEntity::getOrgId, orgId);

            updateWrapper.set(OrgEntity::getLogo, objectKey);

            this.update(updateWrapper);

            URL objectUrl = ossService.getObjectUrl(OssConfiguration.bucket, objectKey);
            return objectUrl.toString();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("upload fail");
        }

    }

    @Override
    public String getLogo() {

        String workspaceId = getWorkspaceId();
        String orgId = getOrgId();
        LambdaQueryWrapper<OrgEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrgEntity::getWorkspaceId, workspaceId);
        wrapper.eq(OrgEntity::getOrgId, orgId);
        OrgEntity orgEntity = this.getOne(wrapper);

        if (orgEntity != null) {
            URL objectUrl = ossService.getObjectUrl(OssConfiguration.bucket, orgEntity.getLogo());
            return objectUrl.toString();
        } else {
            throw new RuntimeException("org is null");
        }
    }


}



