const syncSettings = require('../lib/main')
const gistApi = require('../lib/location/gist')
const SyncSettings = require('../lib/sync-settings')
const fs = require('fs-extra')
const path = require('path')

describe('integration', () => {
	it('should activate and deactivate without error', async () => {
		atom.config.set('sync-settings.checkForUpdatedBackup', false)
		spyOn(console, 'error').and.callThrough()
		await atom.packages.activatePackage('sync-settings')
		// wait for package to activate
		await syncSettings.activationPromise
		await atom.packages.deactivatePackage('sync-settings')

		expect(console.error).not.toHaveBeenCalled()
	})

	it('should check backup on activation', async () => {
		spyOn(SyncSettings.prototype, 'checkBackup')
		spyOn(atom.packages, 'hasActivatedInitialPackages').and.returnValue(true)
		await atom.packages.activatePackage('sync-settings')
		await syncSettings.activationPromise

		expect(SyncSettings.prototype.checkBackup).toHaveBeenCalled()

		await atom.packages.deactivatePackage('sync-settings')
	})

	describe('commands', () => {
		beforeEach(async () => {
			atom.config.set('sync-settings.backupLocation', 'gist')
			await atom.packages.activatePackage('sync-settings')
			await syncSettings.activationPromise
		})

		afterEach(async () => {
			await atom.packages.deactivatePackage('sync-settings')
		})

		it('backup', async () => {
			spyOn(SyncSettings.prototype, 'backup')
			await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:backup')

			expect(SyncSettings.prototype.backup).toHaveBeenCalled()
		})

		it('restore', async () => {
			spyOn(SyncSettings.prototype, 'restore')
			await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:restore')

			expect(SyncSettings.prototype.restore).toHaveBeenCalled()
		})

		it('view backup', async () => {
			spyOn(SyncSettings.prototype, 'viewBackup')
			await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:view-backup')

			expect(SyncSettings.prototype.viewBackup).toHaveBeenCalled()
		})

		it('check backup', async () => {
			spyOn(SyncSettings.prototype, 'checkBackup')
			await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:check-backup')

			expect(SyncSettings.prototype.checkBackup).toHaveBeenCalled()
		})

		it('fork backup', async () => {
			spyOn(SyncSettings.prototype, 'fork')
			await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:fork')

			expect(SyncSettings.prototype.fork).toHaveBeenCalled()
		})
	})

	// FIXME: not sure why linux api test is timing out
	if (process.env.GITHUB_TOKEN && process.platform !== 'linux') {
		describe('API', () => {
			beforeEach(async () => {
				await fs.writeFile(atom.keymaps.getUserKeymapPath(), '# keymap')
				await fs.writeFile(atom.styles.getUserStyleSheetPath(), '// stylesheet')
				await fs.writeFile(atom.getUserInitScriptPath(), '# init')
				await fs.writeFile(path.resolve(atom.getConfigDirPath(), 'snippets.cson'), '# snippets')

				atom.config.set('sync-settings.gistDescription', 'Test gist by Sync Settings for Atom https://github.com/atom-community/sync-settings')

				await gistApi.create()
				await atom.packages.activatePackage('sync-settings')
				await syncSettings.activationPromise
			})

			afterEach(async () => {
				await gistApi.delete()
				await atom.packages.deactivatePackage('sync-settings')
				await fs.unlink(atom.keymaps.getUserKeymapPath())
				await fs.unlink(atom.styles.getUserStyleSheetPath())
				await fs.unlink(atom.getUserInitScriptPath())
				await fs.unlink(path.resolve(atom.getConfigDirPath(), 'snippets.cson'))
			})

			it('backs up files', async () => {
				atom.config.set('sync-settings.gistDescription', 'automatic update by http://atom.io/packages/sync-settings')
				await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:backup')
				const gist = await gistApi.get()
				expect(gist).toEqual({
					time: jasmine.stringMatching(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ$/),
					history: [
						jasmine.objectContaining({
							version: jasmine.stringMatching(/^\w+$/),
						}),
						jasmine.objectContaining({
							version: jasmine.stringMatching(/^\w+$/),
						}),
					],
					files: {
						README: jasmine.any(Object),
						'init.coffee': jasmine.any(Object),
						'keymap.cson': jasmine.any(Object),
						'packages.json': jasmine.any(Object),
						'settings.json': jasmine.any(Object),
						'snippets.cson': jasmine.any(Object),
						'styles.less': jasmine.any(Object),
					},
				})
				expect(gist.files.README.content.toString()).toBe('# Generated by Sync Settings for Atom\n\n<https://github.com/atom-community/sync-settings>')
				expect(gist.files['init.coffee'].content.toString()).toBe('# init')
				expect(gist.files['keymap.cson'].content.toString()).toBe('# keymap')
				expect(gist.files['packages.json'].content.toString()).toEqual(jasmine.stringMatching(/about/))
				expect(gist.files['settings.json'].content.toString()).toEqual(jasmine.stringMatching(/"sync-settings":/))
				expect(gist.files['snippets.cson'].content.toString()).toBe('# snippets')
				expect(gist.files['styles.less'].content.toString()).toBe('// stylesheet')
			}, (process.env.CI ? 60 : 10) * 1000)

			it('restores files', async () => {
				atom.config.set('sync-settings.extraFiles', ['README'])
				await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:restore')
				const readme = await fs.readFile(path.resolve(atom.getConfigDirPath(), 'README'), { encoding: 'utf8' })

				expect(readme).toBe('# Generated by Sync Settings for Atom\n\n<https://github.com/atom-community/sync-settings>')
			}, (process.env.CI ? 60 : 10) * 1000)

			if (!process.env.CI) {
				// CI will get "API rate limit exceeded" error
				it('restores without token', async () => {
					const GITHUB_TOKEN = process.env.GITHUB_TOKEN
					try {
						process.env.GITHUB_TOKEN = ''
						atom.config.set('sync-settings.extraFiles', ['README'])
						await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:restore')
						const readme = await fs.readFile(path.resolve(atom.getConfigDirPath(), 'README'), { encoding: 'utf8' })

						expect(readme).toBe('# Generated by Sync Settings for Atom\n\n<https://github.com/atom-community/sync-settings>')
					} finally {
						process.env.GITHUB_TOKEN = GITHUB_TOKEN
					}
				}, (process.env.CI ? 60 : 10) * 1000)
			}

			it('backs up and restores paths with slash', async () => {
				atom.config.set('sync-settings.extraFiles', ['../test.tmp'])
				const tmpPath = path.resolve(atom.getConfigDirPath(), '../test.tmp')
				await fs.writeFile(tmpPath, 'test.tmp')
				try {
					await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:backup')
					await fs.unlink(tmpPath)
					await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:restore')
					const content = await fs.readFile(tmpPath, { encoding: 'utf8' })

					expect(content).toBe('test.tmp')
				} finally {
					await fs.unlink(tmpPath)
				}
			}, (process.env.CI ? 60 : 10) * 1000)

			it('does not delete a file with only whitespace', async () => {
				atom.config.set('sync-settings.extraFiles', ['README'])
				await fs.writeFile(path.resolve(atom.getConfigDirPath(), 'README'), '\n \t')
				await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:backup')
				const data = await gistApi.get()
				expect('README' in data.files).toBe(true)
				expect(data.files.README.content).toContain('(not found)')
			}, (process.env.CI ? 60 : 10) * 1000)

			it('does delete an unfamiliar file', async () => {
				atom.config.set('sync-settings.extraFiles', ['README'])
				atom.config.set('sync-settings.removeUnfamiliarFiles', true)
				await fs.writeFile(path.resolve(atom.getConfigDirPath(), 'README'), 'README')
				await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:backup')
				await fs.unlink(path.resolve(atom.getConfigDirPath(), 'README'))
				await atom.commands.dispatch(atom.views.getView(atom.workspace), 'sync-settings:backup')
				const data = await gistApi.get()
				expect('README' in data.files).toBe(false)
			}, (process.env.CI ? 60 : 10) * 1000)
		})
	}
})
