import Promise from 'bluebird'
import log from 'npmlog'
import partial from 'lodash/partial'
import { defaults } from 'lodash/object'
import * as creation from './creation'
import * as publishing from './publishing'
import * as assets from './assets'
import * as deletion from './deletion'

const DEFAULT_CONTENT_STRUCTURE = {
  entries: [],
  assets: [],
  contentTypes: [],
  locales: [],
  deletedEntries: [],
  deletedAssets: [],
  deletedContentTypes: [],
  deletedLocales: [],
  webhooks: [],
  editorInterfaces: []
// roles: []
}

/**
 * Pushes all changes, including deletions, to a given space. Handles (un)publishing
 * as well as delays after creation and before publishing.
 *
 * Creates everything in the right order so that a content type for a given entry
 * is there when entry creation for that content type is attempted.
 *
 * Allows only content model or only content pushing.
 *
 * Options:
 * - sourceContent: see DEFAULT_CONTENT_STRUCTURE
 * - destinationContent: see DEFAULT_CONTENT_STRUCTURE
 * - managementClient: preconfigured management API client
 * - spaceId: ID of space content is being copied to
 * - prePublishDelay: milliseconds wait before publishing
 * - contentModelOnly: synchronizes only content types and locales
 * - skipLocales: skips locales when synchronizing the content model
 * - skipContentModel: synchronizes only entries and assets
 * - skipContentPublishing: create content but don't publish it
 */
export default function ({sourceContent, destinationContent = {}, managementClient, spaceId, prePublishDelay, contentModelOnly, skipContentModel, skipLocales, skipContentPublishing}) {
  if (contentModelOnly && skipContentModel) {
    throw new Error('contentModelOnly and skipContentModel cannot be used together')
  }

  if (skipLocales && !contentModelOnly) {
    throw new Error('skipLocales can only be used together with contentModelOnly')
  }

  defaults(sourceContent, DEFAULT_CONTENT_STRUCTURE)
  defaults(destinationContent, DEFAULT_CONTENT_STRUCTURE)

  log.info('Pushing content to destination space')

  return managementClient.getSpace(spaceId)
    .then((space) => {
      let result = Promise.resolve()

      // Unpublish and delete Entries and Assets
      if (!contentModelOnly) {
        result = result
          .then(partial(publishing.unpublishEntities, sourceContent.deletedEntries))
          .delay(prePublishDelay)
          .then(partial(deletion.deleteEntities, sourceContent.deletedEntries))

          .then(partial(publishing.unpublishEntities, sourceContent.deletedAssets))
          .delay(prePublishDelay)
          .then(partial(deletion.deleteEntities, sourceContent.deletedAssets))
      }

      // Unpublish and delete Locales and Content Types
      // Create and publish new Locales and Content Types
      if (!skipContentModel) {
        if (!skipLocales) {
          result = result
            .then(partial(deletion.deleteEntities, sourceContent.deletedLocales))
        }

        result = result
          .then(partial(publishing.unpublishEntities, sourceContent.deletedContentTypes))
          .delay(prePublishDelay)
          .then(partial(deletion.deleteEntities, sourceContent.deletedContentTypes))

        if (!skipLocales) {
          result = result
            .then(partial(creation.createEntities,
              {space: space, type: 'Locale'}, sourceContent.locales, destinationContent.locales))
        }
        result = result
          .then(partial(creation.createEntities,
            {space: space, type: 'ContentType'}, sourceContent.contentTypes, destinationContent.contentTypes))
          .delay(prePublishDelay)
          .then(partial(publishing.publishEntities))
          .then((contentTypes) => {
            let contentTypesWithEditorInterface = contentTypes.map((contentType) => {
              for (let editorInterface of sourceContent.editorInterfaces) {
                if (editorInterface.sys.contentType.sys.id === contentType.sys.id) {
                  return space.getEditorInterfaceForContentType(contentType.sys.id).then((ctEditorInterface) => {
                    ctEditorInterface.controls = editorInterface.controls
                    return ctEditorInterface.update()
                  })
                }
              }
              return Promise.resolve()
            })
            return Promise.all(contentTypesWithEditorInterface)
          })
      }

      // Create and publish Assets and Entries
      if (!contentModelOnly) {
        result = result
          .then(partial(creation.createEntities,
            {space: space, type: 'Webhook'}, sourceContent.webhooks, destinationContent.webhooks))
          .delay(prePublishDelay)

        result = result
          .then(partial(creation.createEntities,
            {space: space, type: 'Asset'}, sourceContent.assets, destinationContent.assets))
          .delay(prePublishDelay)
          .then(partial(assets.processAssets))
          .delay(prePublishDelay)
          .then((entities) => {
            return skipContentPublishing
              ? Promise.resolve([])
              : publishing.publishEntities(entities)
          })
          // Push Drafts
        const drafts = sourceContent.entries.filter((entry) => entry.isDraft)
        sourceContent.entries = sourceContent.entries.filter((entry) => !entry.isDraft)
        result = result
          .then(partial(creation.createEntries,
            {space: space, skipContentModel: skipContentModel}, drafts, []))
        // push published entries
          .then(partial(creation.createEntries,
            {space: space, skipContentModel: skipContentModel}, sourceContent.entries, destinationContent.entries))
          .delay(prePublishDelay)
          .then((entities) => {
            return skipContentPublishing
              ? Promise.resolve([])
              : publishing.publishEntities(entities)
          })
      }

      return result
    })
}

@@ -1469,16 +1469,19 @@
 ction (%7B
+%0A  
 sourceCo
@@ -1538,16 +1538,18 @@
 spaceId,
+%0A 
  prePubl
@@ -1606,16 +1606,18 @@
 Locales,
+%0A 
  skipCon
@@ -1630,16 +1630,17 @@
 blishing
+%0A
 %7D) %7B%0A  i
@@ -5230,25 +5230,47 @@
 filter((
+%7Boriginal: 
 entry
+%7D
 ) =%3E
+%0A         
  entry.i
@@ -5267,32 +5267,34 @@
    entry.isDraft
+()
 )%0A        source
@@ -5287,31 +5287,32 @@
         
-sourceContent.e
+const publishedE
 ntries =
@@ -5345,14 +5345,37 @@
 ter(
-(
+%0A          (%7Boriginal: 
 entry
+%7D
 ) =%3E
@@ -5389,16 +5389,18 @@
 .isDraft
+()
 )%0A      
@@ -5412,39 +5412,75 @@
 ult = result%0A   
+  
+     // create and push drafts%0A
        
+   
 .then(partial(cr
@@ -5590,13 +5590,36 @@
     
+  
 // 
-pu
+create, push, and publi
 sh p
@@ -5746,32 +5746,39 @@
 tModel%7D,
- sourceContent.e
+%0A            publishedE
 ntries, 
@@ -5799,24 +5799,35 @@
 tent.entries
+%0A          
 ))%0A         
@@ -5880,37 +5880,16 @@
 ties) =%3E
- %7B%0A            return
  skipCon
@@ -5987,36 +5987,24 @@
 es(entities)
-%0A          %7D
 )%0A      %7D%0A%0A 

fix drafts exporting