package com.bocloud.ims.service.resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.model.RequestContext.Catalog;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.ims.common.cache.DictionaryCache;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Resource;
import com.bocloud.ims.entity.resource.ResourceGroup;
import com.bocloud.ims.interfaces.resource.ResourceService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.ResourceGroupRepository;
import com.bocloud.ims.repository.resource.ResourceRepository;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * 资源Service接口实现
 *
 * @author weiwei
 */
@Service("resourceService")
public class ResourceServiceImpl implements ResourceService {

    private static Logger logger = LoggerFactory.getLogger(ResourceServiceImpl.class);
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private ResourceGroupRepository resourceGroupRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public BocloudResult<GridBean<Resource>> list(Pager pager, RequestContext context) {
        GridBean gridBean = null;
        try {

            int page = pager.getPage();
            int rows = pager.getRows();
            List<Param> params = pager.getParams();
            Map<String, String> sorter = pager.getSorter();
            boolean simple = pager.getSimple();

            params = Optional.ofNullable(params).orElse(new ArrayList<>());
            sorter = Optional.ofNullable(sorter).orElse(Maps.newHashMap());
            sorter.put(Common.ID, Common.ONE);
            Long tenantId = context.getTenant();
            // 为租户下的用户
            if (null != tenantId && 0L != tenantId) {
                Long userId = Catalog.User == context.getCatalog() ? context.getTarget() : null;
                List<Resource> resources = resourceRepository.list(page, rows, params, sorter, tenantId, userId);
                int total = this.resourceRepository.count(params, tenantId, userId);
                gridBean = GridHelper.getBean(page, rows, total, resources);
            } else {
                List<Resource> resources = resourceRepository.list(page, rows, params, sorter);
                for (Resource resource : resources) {
                    if (null != resource.getVendorId()) {
                        CloudVendor vendor = cloudVendorRepository.query(resource.getVendorId());
                        if (null != vendor) {
                            resource.setVendorName(vendor.getName());
                        }
                    }
                    if (null != resource.getGroupIds()) {
                        String names = JSONObject.parseArray(resource.getGroupIds(), Long.class).stream()
                            .map(o -> resourceGroupRepository.query(o)).map(ResourceGroup::getName)
                            .collect(Collectors.joining(", "));
                        resource.setGroupsName(names);
                    }
                    resource.setResourceGroupName(DictionaryCache.readCache(resource.getResourceGroup()));
                }
                int total = this.resourceRepository.count(params);
                gridBean = GridHelper.getBean(page, rows, total, resources);
            }
        } catch (Exception e) {
            logger.error("list resource error:", e);
            return new BocloudResult<>(false, "查询失败");
        }
        return new BocloudResult<>(true, gridBean, "查询成功");
    }

    @Override
    public BocloudResult create(Resource resource, RequestContext context) {
        try {
            if (resource.getVendorId() == null) {
                return new BocloudResult<>(false, "需要参数vendorId");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(resource.getVendorId());
            if (cloudVendor == null || cloudVendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或该平台已经被删除");
            }
            ResourceService service = applicationContext.getBean(
                cloudVendor.getType().toLowerCase() + ResourceService.class.getSimpleName(), ResourceService.class);
            return service.create(resource, context);
        } catch (Exception e) {
            logger.error("创建失败：", e);
            return new BocloudResult<>(false, "创建失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult modify(String params, RequestContext context) {
        try {
            Resource resource = JSONObject.parseObject(params, Resource.class);
            if (resource.getVendorId() == null) {
                return new BocloudResult<>(false, "需要参数vendorId");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(resource.getVendorId());
            if (cloudVendor == null || cloudVendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或该平台已经被删除");
            }
            ResourceService service = applicationContext.getBean(
                cloudVendor.getType().toLowerCase() + ResourceService.class.getSimpleName(), ResourceService.class);
            return service.modify(params, context);
        } catch (Exception e) {
            logger.error("修改失败：", e);
            return new BocloudResult<>(false, "修改失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult patch(String action, String params, RequestContext context) {
        try {
            JSONObject object = JSONObject.parseObject(params, JSONObject.class);
            CloudVendor cloudVendor = cloudVendorRepository.query(object.getLong("vendorId"));
            if (cloudVendor == null || cloudVendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或该平台已经被删除");
            }
            ResourceService service = applicationContext.getBean(
                cloudVendor.getType().toLowerCase() + ResourceService.class.getSimpleName(), ResourceService.class);
            return service.patch(action, params, context);
        } catch (BeansException e) {
            logger.error("操作失败：", e);
            return new BocloudResult<>(false, "操作失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult patch(Long id, String action, String params, String agent, RequestContext context) {
        try {
            Resource resource = resourceRepository.query(id);
            if (resource == null || resource.getDeleted()) {
                return new BocloudResult<>(false, "未找到资源或该资源已经被删除");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(resource.getVendorId());
            if (cloudVendor == null || cloudVendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或该平台已经被删除");
            }
            ResourceService service = applicationContext.getBean(
                cloudVendor.getType().toLowerCase() + ResourceService.class.getSimpleName(), ResourceService.class);
            return service.patch(id, action, params, agent, context);
        } catch (BeansException e) {
            logger.error("操作失败：", e);
            return new BocloudResult<>(false, "操作失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult delete(Long id, String params, RequestContext context) {
        try {
            Resource resource = resourceRepository.get(Resource.class, id);
            if (resource == null) {
                return new BocloudResult<>(true, "删除成功");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(resource.getVendorId());
            if (cloudVendor == null || cloudVendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或该平台已经被删除");
            }
            ResourceService service = applicationContext.getBean(
                cloudVendor.getType().toLowerCase() + ResourceService.class.getSimpleName(), ResourceService.class);
            return service.delete(id, params, context);
        } catch (BeansException e) {
            logger.error("删除失败：", e);
            return new BocloudResult<>(false, "删除失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult accessClient(String params, RequestContext context) {
        try {
            JSONObject object = JSONObject.parseObject(params, JSONObject.class);
            if (object.getLong("vendorId") == null) {
                return new BocloudResult<>(false, "需要参数vendorId");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(object.getLong("vendorId"));
            if (cloudVendor == null || cloudVendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或该平台已经被删除");
            }
            ResourceService service = applicationContext.getBean(
                cloudVendor.getType().toLowerCase() + ResourceService.class.getSimpleName(), ResourceService.class);
            return service.accessClient(params, context);
        } catch (Exception e) {
            logger.error("获取accessClient失败：", e);
            return new BocloudResult<>(false, "获取accessClient失败：" + e.getMessage());
        }
    }

    @Override
    public BocloudResult detail(Long id, String params, String type) {
        try {
            JSONObject object = JSONObject.parseObject(params, JSONObject.class);
            if (object.getLong("vendorId") == null) {
                return new BocloudResult<>(false, "需要参数vendorId");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(object.getLong("vendorId"));
            if (cloudVendor == null || cloudVendor.getDeleted()) {
                return new BocloudResult<>(false, "未找到平台或该平台已经被删除");
            }
            ResourceService service = applicationContext.getBean(
                cloudVendor.getType().toLowerCase() + ResourceService.class.getSimpleName(), ResourceService.class);
            return service.detail(id, params, type);
        } catch (Exception e) {
            logger.error("获取失败：", e);
            return new BocloudResult<>(false, "获取失败：" + e.getMessage());
        }
    }

    @Override
    public Resource getByHost(String host) {
        try {
            return this.resourceRepository.getByHost(host, ResourceCategory.Computer.name());
        } catch (Exception e) {
            logger.error("Get resource error:", e);
            return null;
        }
    }

    @Override
    public Resource query(Long id) {
        try {
            Resource resource = resourceRepository.query(id);
            return resource;
        } catch (Exception e) {
            logger.error("get resource error", e);
            return null;
        }
    }

    @Override
    public BocloudResult<Resource> detail(Long id) {
        try {
            Resource resource = resourceRepository.query(id);
            if (null != resource.getGroupIds()) {
                List<String> names = JSONObject.parseArray(resource.getGroupIds(), Long.class).stream()
                    .map(o -> resourceGroupRepository.query(o)).map(ResourceGroup::getName)
                    .collect(Collectors.toList());
                resource.setGroupsName(names.isEmpty() ? null : JSONObject.toJSONString(names));
            }
            resource.setResourceGroupName(DictionaryCache.readCache(resource.getResourceGroup()));
            return new BocloudResult<>(true, resource, "查询成功!");
        } catch (Exception e) {
            logger.error("get resource failure:", e);
            return new BocloudResult<>(false, "查询失败!");
        }
    }

    @Override
    public BocloudResult<String> modifyAccount(String params, RequestContext context) {
        JSONObject object = JSONTools.isJSONObj(params);
        if (null == object) {
            return new BocloudResult<>(false, "参数格式错误");
        }
        Resource resource = new Resource();
        if (object.getLong("id") == null) {
            return new BocloudResult<>(false, "参数格式错误");
        }
        try {
            Resource queryResource = resourceRepository.queryByTargetId(object.getLong("id"));
            if (queryResource == null) {
                return new BocloudResult<>(false, "数据不存在");
            }
            resource.setId(queryResource.getId());
        } catch (Exception e) {
            return new BocloudResult<>(false, "数据不存在");
        }

        resource.setUsername(object.getString("username"));
        resource.setPassword(object.getString("password"));

        try {
            resourceRepository.updateAccount(resource);
        } catch (Exception e) {
            logger.error("update resource error:", e);
            return new BocloudResult<>(false, "修改失败");
        }
        return new BocloudResult<>(true, "修改成功");
    }

    @Override
    public BocloudResult queryAccount(Long targetId) {
        try {
            Resource resource = resourceRepository.queryByTargetId(targetId);
            return new BocloudResult<>(true, resource, "查询成功");
        } catch (Exception e) {
            logger.error("get resource error", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult allot(String ids, Long userId) {
        if (StringUtils.isEmpty(ids)) {
            return new BocloudResult<>(false, "请求数据有误");
        }
        String[] values = ids.split(",");
        List<String> fails = Lists.newArrayList();
        try {
            for (String value : values) {
                Long id = Long.valueOf(value);
                Resource resource = resourceRepository.query(id);
                if (null == resource) {
                    continue;
                }
                BocloudResult result = allot(resource, userId);
                if (result.isFailed()) {
                    fails.add(resource.getName());
                }
            }
        } catch (Exception e) {
            logger.error("allot resources to project", e);
            return new BocloudResult<>(false, "资源分配失败");
        }
        if (fails.isEmpty()) {
            return new BocloudResult<>(true, "资源分配成功");
        }
        StringBuffer buffer = new StringBuffer("【");
        for (String fail : fails) {
            buffer.append(fail + " ");
        }
        String message = buffer.toString().trim() + "】";
        return new BocloudResult<>(false, "资源分配失败:资源" + message + "存在分配有误");
    }

    private BocloudResult allot(Resource resource, Long userId) {
        String path = Resource.class.getSimpleName() + "_" + resource.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            if (ResourceCatalog.LOGICAL.name().equals(resource.getCatalog())) {
                CloudServer server = cloudServerRepository.query(resource.getTarget());
                if (null != server) {
                    server.setMenderId(userId);
                    server.setGmtModify(new Date());
                    cloudServerRepository.update(server);
                }
            }
            resource.setMenderId(userId);
            resource.setGmtModify(new Date());
            resourceRepository.update(resource);
            return new BocloudResult<>(true, "资源分配成功");
        } catch (Exception e) {
            logger.error("allot resource to project", e);
            return new BocloudResult<>(false, "资源分配失败");
        }
    }

    @Override
    public BocloudResult recycle(Long id, Long userId) {
        String path = Resource.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            Resource resource = resourceRepository.query(id);
            if (null == resource) {
                return new BocloudResult<>(false, "该资源不存在");
            }
            if (ResourceCatalog.LOGICAL.name().equals(resource.getCatalog())) {
                CloudServer server = cloudServerRepository.query(resource.getTarget());
                if (null != server) {
                    server.setMenderId(userId);
                    server.setGmtModify(new Date());
                    cloudServerRepository.update(server);
                }
            }
            resource.setMenderId(userId);
            resource.setGmtModify(new Date());
            resourceRepository.update(resource);
            return new BocloudResult<>(true, "资源回收成功");
        } catch (Exception e) {
            logger.error("allot resource to project", e);
            return new BocloudResult<>(false, "资源回收失败");
        }
    }

    @Override
    public BocloudResult migrate(Long resourceId, Long groupId, String groupIds, RequestContext context) {
        try {
            Resource resource = resourceRepository.query(resourceId);
            if (null == resource) {
                logger.warn("resource not exists");
                return new BocloudResult<>(false, "资源不存在");
            }
            resourceRepository.migrate(resourceId, groupId, groupIds, context);
        } catch (Exception e) {
            logger.error("migrate is error", e);
            return new BocloudResult<>(false, "迁移失败");
        }
        return new BocloudResult<>(true, "迁移成功");
    }

    @Override
    public BocloudResult<Long> queryId(Long target, String catalog) {
        try {
            Resource resource = resourceRepository.query(target, catalog);
            return new BocloudResult<>(true, resource.getId(), "查询成功");
        } catch (Exception e) {
            logger.error("query is error", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<Long> resources(String condition) {
        JSONObject object = JSONObject.parseObject(condition);
        String type = null;

        type = object.getString("type");
        Long target = object.getLong("target");
        String catalog = object.getString("catalog");
        if (null != target && null != catalog) {
            return this.queryId(target, catalog);
        }
        return new BocloudResult<>(false, "查询失败");

    }
}
