package com.ge.predix.acs.privilege.management.dao;

import java.util.List;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

@Component
@Profile("titan")
public final class TitanMigrationManager {
    private static final Logger LOGGER = LoggerFactory.getLogger(TitanMigrationManager.class);

    @Autowired
    @Qualifier("resourceRepository")
    private ResourceRepository resourceRepository;

    @Autowired
    @Qualifier("resourceHierarchicalRepository")
    private GraphResourceRepository resourceHierarchicalRepository;

    @Autowired
    @Qualifier("subjectRepository")
    private SubjectRepository subjectRepository;

    @Autowired
    @Qualifier("subjectHierarchicalRepository")
    private GraphSubjectRepository subjectHierarchicalRepository;

    private static final int PAGE_SIZE = 100;

    public static int getPageSize() {
        return PAGE_SIZE;
    }

    public TitanMigrationManager(final ResourceRepository resourceRepository,
            final GraphResourceRepository resourceHierarchicalRepository, final SubjectRepository subjectRepository,
            final GraphSubjectRepository subjectHierarchicalRepository) {
        this.resourceRepository = resourceRepository;
        this.resourceHierarchicalRepository = resourceHierarchicalRepository;
        this.subjectRepository = subjectRepository;
        this.subjectHierarchicalRepository = subjectHierarchicalRepository;
    }

    public TitanMigrationManager() {

    }

    private void doResourceMigration() {
        int totalResources = 0;
        Pageable pageRequest = new PageRequest(0, PAGE_SIZE);
        long numOfResourceEntitiesToMigrate = resourceRepository.count();
        Page<ResourceEntity> pageOfResources = resourceRepository.findAll(pageRequest);

        do {
            List<ResourceEntity> listOfResources = pageOfResources.getContent();
            totalResources += pageOfResources.getNumberOfElements();
            // Clear the auto-generated id field prior to migrating to graphDB
            listOfResources.forEach(item -> item.setId((long) 0));
            resourceHierarchicalRepository.save(listOfResources);
            LOGGER.info("Total migrated so far: " + totalResources + "/" + numOfResourceEntitiesToMigrate);
            pageRequest = pageOfResources.nextPageable();
        } while (pageOfResources.hasNext());

        LOGGER.info("Number of resource entities migrated: " + totalResources);
        LOGGER.info("Resource migration to Titan completed.");
    }

    private void doSubjectMigration() {
        int totalSubjects = 0;
        Pageable pageRequest = new PageRequest(0, PAGE_SIZE);
        long numOfSubjectEntitiesToMigrate = subjectRepository.count();
        Page<SubjectEntity> pageOfSubjects = subjectRepository.findAll(pageRequest);

        do {
            List<SubjectEntity> listOfSubjects = pageOfSubjects.getContent();
            totalSubjects += pageOfSubjects.getNumberOfElements();
            listOfSubjects.forEach(item -> item.setId((long) 0));
            subjectHierarchicalRepository.save(listOfSubjects);
            LOGGER.info("Total migrated so far: " + totalSubjects + "/" + numOfSubjectEntitiesToMigrate);
            pageRequest = pageOfSubjects.nextPageable();
        } while (pageOfSubjects.hasNext());

        LOGGER.info("Number of subject entities migrated: " + totalSubjects);
        LOGGER.info("Subject migration to Titan completed.");

    }

    @PostConstruct
    public void doMigration() {
        try {

            // This version vertex is common to both subject and resource repositories. So this check is sufficient to
            // trigger migrations in both repos.
            if (this.resourceHierarchicalRepository.getVersion() == 0) {

                LOGGER.info("Starting attribute migration process to Titan.");
                doResourceMigration();
                doSubjectMigration();
                this.resourceHierarchicalRepository.setVersion(1);
                LOGGER.info("Exiting from Titan attribute migration process.");

            }
            return;
        } catch (Throwable e) {
            LOGGER.error("Exception doing migration: ", e);
        }
    }
}
@@ -1932,21 +1932,21 @@
     int 
-total
+numOf
 Resource
@@ -1946,16 +1946,21 @@
 esources
+Saved
  = 0;%0A  
@@ -2117,24 +2117,67 @@
 ourceEntity%3E
+ pageOfResources;%0A%0A        do %7B%0A           
  pageOfResou
@@ -2219,38 +2219,24 @@
 ageRequest);
-%0A%0A        do %7B
 %0A           
@@ -2257,31 +2257,34 @@
 Entity%3E 
-listOfResources
+resourceListToSave
  = pageO
@@ -2320,21 +2320,21 @@
         
-total
+numOf
 Resource
@@ -2334,16 +2334,21 @@
 esources
+Saved
  += page
@@ -2473,31 +2473,34 @@
         
-listOfResources
+resourceListToSave
 .forEach
@@ -2583,23 +2583,26 @@
 ave(
-listOfResources
+resourceListToSave
 );%0A 
@@ -2616,38 +2616,69 @@
     LOGGER.info(
-%22Total
+%0A                    %22Total resources
  migrated so far
@@ -2679,29 +2679,29 @@
 so far: %22 + 
-total
+numOf
 Resources + 
@@ -2697,16 +2697,21 @@
 esources
+Saved
  + %22/%22 +
@@ -2911,21 +2911,21 @@
 ed: %22 + 
-total
+numOf
 Resource
@@ -2925,16 +2925,21 @@
 esources
+Saved
 );%0A     
@@ -3055,29 +3055,29 @@
     int 
-total
+numOf
 Subjects
  = 0;%0A  
@@ -3068,16 +3068,21 @@
 Subjects
+Saved
  = 0;%0A  
@@ -3236,24 +3236,66 @@
 bjectEntity%3E
+ pageOfSubjects;%0A%0A        do %7B%0A           
  pageOfSubje
@@ -3340,30 +3340,19 @@
 quest);%0A
-%0A
    
-     do %7B%0A
         
@@ -3348,27 +3348,24 @@
             
-   
 List%3CSubject
@@ -3372,30 +3372,33 @@
 Entity%3E 
-listOfSubjects
+subjectListToSave
  = pageO
@@ -3433,29 +3433,29 @@
         
-total
+numOf
 Subjects
  += page
@@ -3446,16 +3446,21 @@
 Subjects
+Saved
  += page
@@ -3505,30 +3505,33 @@
         
-listOfSubjects
+subjectListToSave
 .forEach
@@ -3613,22 +3613,25 @@
 ave(
-listOfSubjects
+subjectListToSave
 );%0A 
@@ -3660,16 +3660,25 @@
 (%22Total 
+subjects 
 migrated
@@ -3690,29 +3690,29 @@
 ar: %22 + 
-total
+numOf
 Subjects
  + %22/%22 +
@@ -3703,16 +3703,21 @@
 Subjects
+Saved
  + %22/%22 +
@@ -3917,21 +3917,21 @@
 %22 + 
-total
+numOf
 Subjects
 );%0A 
@@ -3926,16 +3926,21 @@
 Subjects
+Saved
 );%0A     

Fix pagination for ACS attribute migration.