package org.exoplatform.cs.service;

import org.exoplatform.services.cms.BasePath;
import org.exoplatform.services.cms.documents.DocumentService;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.access.PermissionType;
import org.exoplatform.services.jcr.core.ExtendedNode;
import org.exoplatform.services.jcr.ext.app.SessionProviderService;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.jcr.ext.distribution.DataDistributionManager;
import org.exoplatform.services.jcr.ext.distribution.DataDistributionMode;
import org.exoplatform.services.jcr.ext.distribution.DataDistributionType;
import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.social.core.space.model.Space;
import org.exoplatform.social.core.space.spi.SpaceService;
import org.exoplatform.upload.UploadResource;
import org.exoplatform.upload.UploadService;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

public class TicketAttachmentServiceImpl implements TicketAttachmentService {

    private static final Log LOG = ExoLogger.getLogger(TicketAttachmentServiceImpl.class);

    public static final String CS_TICKET_ATTACHMENTS_NODES_FOLDER = "Cs Ticket Attachments";
    public static final String DOCUMENTS_FOLDER =  "/Documents";

    private SessionProviderService sessionProviderService;

    private RepositoryService repositoryService;

    private NodeHierarchyCreator nodeHierarchyCreator;

    private DataDistributionType dataDistributionType;

    private SpaceService spaceService;

    private UploadService uploadService;

    private DocumentService documentService;

    public TicketAttachmentServiceImpl(SessionProviderService sessionProviderService, RepositoryService repositoryService,
                                       NodeHierarchyCreator nodeHierarchyCreator, DataDistributionManager dataDistributionManager,
                                       SpaceService spaceService, UploadService uploadService, DocumentService documentService) {
        this.sessionProviderService = sessionProviderService;
        this.repositoryService = repositoryService;
        this.nodeHierarchyCreator = nodeHierarchyCreator;
        this.dataDistributionType = dataDistributionManager.getDataDistributionType(DataDistributionMode.NONE);;
        this.spaceService = spaceService;
        this.uploadService = uploadService;
        this.documentService = documentService;
    }

    private String getNodeRelativePath(Calendar now) {
        return now.get(Calendar.YEAR) + "/" + (now.get(Calendar.MONTH) + 1) + "/" + now.get(Calendar.DAY_OF_MONTH);
    }

    private Node getCsTicketAttachmentsRootNode(String spaceGroupId, Session session) throws RepositoryException {
        String groupPath = nodeHierarchyCreator.getJcrPath(BasePath.CMS_GROUPS_PATH);
        String spaceDocumentsFolderPath = groupPath + spaceGroupId + DOCUMENTS_FOLDER;

        Node spaceDocumentsFolderNode = (Node) session.getItem(spaceDocumentsFolderPath);

        Node spaceCsTicketRootNode;
        if(!spaceDocumentsFolderNode.hasNode(CS_TICKET_ATTACHMENTS_NODES_FOLDER)) {
            spaceCsTicketRootNode = spaceDocumentsFolderNode.addNode(CS_TICKET_ATTACHMENTS_NODES_FOLDER, "nt:unstructured");
            if(spaceCsTicketRootNode.canAddMixin("exo:privilegeable")) {
                spaceCsTicketRootNode.addMixin("exo:privilegeable");
            }
            Map<String, String[]> permissions = new HashMap<>();
            permissions.put("*:/platform/administrators", PermissionType.ALL);
            permissions.put("*:" + spaceGroupId, PermissionType.ALL);
            ((ExtendedNode) spaceCsTicketRootNode).setPermissions(permissions);
            spaceDocumentsFolderNode.save();
        } else {
            spaceCsTicketRootNode = spaceDocumentsFolderNode.getNode(CS_TICKET_ATTACHMENTS_NODES_FOLDER);
        }
        return spaceCsTicketRootNode;
    }

    @Override
    public String addAttachmentFromUploadedResource(String cSpaceGroupId, String uploadId) throws Exception {
        UploadResource uploadedResource = uploadService.getUploadResource(uploadId);
        if (uploadedResource == null) {
            throw new Exception("Cannot attach uploaded file " + uploadId + ", it may not exist");
        }
        if (cSpaceGroupId == null) {
            throw new Exception("customer space id is mandatory");
        }
        SessionProvider sessionProvider = sessionProviderService.getSystemSessionProvider(null);
        Session session = sessionProvider.getSession( repositoryService.getCurrentRepository()
                                                                        .getConfiguration()
                                                                        .getDefaultWorkspaceName(),
                                                                        repositoryService.getCurrentRepository());

        Node spaceNewsAttachmentsRootNode = getCsTicketAttachmentsRootNode(cSpaceGroupId, session);
        Node csTicketAttachmentsFolderNode = dataDistributionType.getOrCreateDataNode(spaceNewsAttachmentsRootNode, getNodeRelativePath(Calendar.getInstance()));

        Node attachmentNode = csTicketAttachmentsFolderNode.addNode(uploadedResource.getFileName(), "nt:file");
        attachmentNode.addMixin("mix:versionable");
        attachmentNode.setProperty("exo:title", uploadedResource.getFileName());
        Node resourceNode = attachmentNode.addNode("jcr:content", "nt:resource");
        resourceNode.setProperty("jcr:mimeType", uploadedResource.getMimeType());
        Calendar now = Calendar.getInstance();
        resourceNode.setProperty("jcr:lastModified", now);
        resourceNode.setProperty("exo:dateModified", now);
        String fileDiskLocation = uploadedResource.getStoreLocation();
        if(fileDiskLocation != null) {
            try (InputStream inputStream = new FileInputStream(fileDiskLocation)) {
                resourceNode.setProperty("jcr:data", inputStream);
                csTicketAttachmentsFolderNode.save();
            }
        } else {
            csTicketAttachmentsFolderNode.save();
        }
        return attachmentNode.getUUID();
    }

    @Override
    public String addAttachmentFromExistingResource(String attachmentId) throws Exception {
        return  attachmentId;
    }
}
