import { device, waitFor, element, by, expect } from 'detox';

import data from '../../data';
import {
	navigateToLogin,
	tapBack,
	login,
	sleep,
	platformTypes,
	TTextMatcher,
	navigateToRoom,
	jumpToQuotedMessage
} from '../../helpers/app';

let textMatcher: TTextMatcher;
let alertButtonType: string;

async function clearCache() {
	await waitFor(element(by.id('room-view')))
		.toBeVisible()
		.withTimeout(5000);
	await tapBack();
	await waitFor(element(by.id('rooms-list-view')))
		.toBeVisible()
		.withTimeout(10000);
	await element(by.id('rooms-list-view-sidebar')).tap();
	await sleep(300); // wait animation
	await waitFor(element(by.id('sidebar-settings')))
		.toBeVisible()
		.withTimeout(2000);
	await element(by.id('sidebar-settings')).tap();
	await sleep(300); // wait animation
	await waitFor(element(by.id('settings-view-clear-cache')))
		.toBeVisible()
		.withTimeout(2000);
	await element(by.id('settings-view-clear-cache')).tap();
	await waitFor(element(by[textMatcher]('This will clear all your offline data.')))
		.toExist()
		.withTimeout(2000);
	await element(by[textMatcher]('Clear').and(by.type(alertButtonType))).tap();
	await waitFor(element(by.id('rooms-list-view')))
		.toBeVisible()
		.withTimeout(5000);
	await waitFor(element(by.id('rooms-list-view-item-jumping')))
		.toExist()
		.withTimeout(10000);
}

async function waitForLoading() {
	// if (device.getPlatform() === 'android') {
	await sleep(10000);
	// 	return; // FIXME: Loading indicator doesn't animate properly on android
	// }
	// await waitFor(element(by.id('loading-image')))
	// 	.toBeVisible()
	// 	.withTimeout(5000);
	// await waitFor(element(by.id('loading-image')))
	// 	.toBeNotVisible()
	// 	.withTimeout(10000);
}

function getIndex() {
	if (device.getPlatform() === 'android') {
		return 1;
	}
	return 0;
}

describe('Room', () => {
	beforeAll(async () => {
		await device.launchApp({ permissions: { notifications: 'YES' }, delete: true });
		({ alertButtonType, textMatcher } = platformTypes[device.getPlatform()]);
		await navigateToLogin();
		await login(data.adminUser, data.adminPassword);
	});

	it('should jump to an old message and load its surroundings', async () => {
		if (device.getPlatform() === 'android') {
			return;
		}
		await navigateToRoom('jumping');
		await waitFor(element(by[textMatcher]('295')))
			.toExist()
			.withTimeout(5000);
		await sleep(2000);
		await jumpToQuotedMessage(element(by[textMatcher]('1')).atIndex(0));
		await waitForLoading();
		await waitFor(element(by[textMatcher]('1')).atIndex(0))
			.toExist()
			.withTimeout(30000);
		await expect(element(by[textMatcher]('2'))).toExist();
	});

	it('should tap FAB and scroll to bottom', async () => {
		if (device.getPlatform() === 'android') {
			return;
		}
		await waitFor(element(by.id('nav-jump-to-bottom')))
			.toExist()
			.withTimeout(15000);
		await element(by.id('nav-jump-to-bottom')).tap();
		await waitFor(element(by[textMatcher]("Go to jumping-thread's thread")))
			.toExist()
			.withTimeout(15000);
		await clearCache();
	});

	it('should load messages on scroll', async () => {
		if (device.getPlatform() === 'android') {
			return;
		}
		await navigateToRoom('jumping');
		await waitFor(element(by.id('room-view-messages')))
			.toExist()
			.withTimeout(5000);
		await waitFor(element(by[textMatcher]('300')))
			.toExist()
			.withTimeout(30000);
		let found = false;
		while (!found) {
			try {
				const direction = device.getPlatform() === 'android' ? 'down' : 'up';
				await element(by.id('room-view-messages')).scroll(500, direction);
				await expect(element(by[textMatcher]('249'))).toExist();
				found = true;
			} catch {
				//
			}
		}
		await clearCache();
	});

	it('should search for old message and load its surroundings', async () => {
		if (device.getPlatform() === 'android') {
			return;
		}
		await navigateToRoom('jumping');
		await sleep(1000); // wait for proper load the room
		await element(by.id('room-view-search')).tap();
		await waitFor(element(by.id('search-messages-view')))
			.toExist()
			.withTimeout(5000);
		await element(by.id('search-message-view-input')).replaceText('30');
		await waitFor(element(by[textMatcher]('30')).atIndex(getIndex()))
			.toExist()
			.withTimeout(30000);
		await sleep(1000);
		await element(by[textMatcher]('30')).atIndex(getIndex()).tap();
		await waitForLoading();
		await waitFor(element(by[textMatcher]('30')).atIndex(0))
			.toExist()
			.withTimeout(30000);
		await expect(element(by[textMatcher]('31'))).toExist();
		await expect(element(by[textMatcher]('32'))).toExist();
	});

	it('should load newer and older messages', async () => {
		if (device.getPlatform() === 'android') {
			return;
		}
		let found = false;
		while (!found) {
			try {
				// it doesn't recognize this list
				await element(by.id('room-view-messages')).scroll(500, 'up');
				await expect(element(by[textMatcher]('Load older'))).toBeVisible();
				await expect(element(by[textMatcher]('5'))).toExist();
				found = true;
			} catch {
				//
			}
		}
		await element(by[textMatcher]('Load older')).atIndex(0).tap();
		await waitFor(element(by[textMatcher]('4')))
			.toExist()
			.withTimeout(5000);
		await element(by.id('room-view-messages')).atIndex(0).swipe('down', 'fast', 0.5);
		await waitFor(element(by[textMatcher]('1')))
			.toExist()
			.withTimeout(5000);
		await element(by.id('room-view-messages')).atIndex(0).swipe('up', 'fast', 0.5);
		await waitFor(element(by[textMatcher]('25')))
			.toExist()
			.withTimeout(5000);
		await element(by.id('room-view-messages')).atIndex(0).swipe('up', 'fast', 0.5);
		await waitFor(element(by[textMatcher]('50')))
			.toExist()
			.withTimeout(5000);
		await element(by.id('room-view-messages')).atIndex(0).swipe('up', 'slow', 0.3);
		await waitFor(element(by[textMatcher]('Load newer')))
			.toExist()
			.withTimeout(5000);
		await element(by[textMatcher]('Load newer')).atIndex(0).tap();
		await waitFor(element(by[textMatcher]('104')))
			.toExist()
			.withTimeout(5000);
		await waitFor(element(by[textMatcher]('Load newer')))
			.toExist()
			.withTimeout(5000);
		await element(by[textMatcher]('Load newer')).atIndex(0).tap();
		await waitFor(element(by[textMatcher]('154')))
			.toExist()
			.withTimeout(5000);
		await waitFor(element(by[textMatcher]('Load newer')))
			.toExist()
			.withTimeout(5000);
		await element(by[textMatcher]('Load newer')).atIndex(0).tap();
		await waitFor(element(by[textMatcher]('202')))
			.toExist()
			.withTimeout(5000);
		await waitFor(element(by[textMatcher]('Load newer')))
			.toNotExist()
			.withTimeout(5000);
		await expect(element(by[textMatcher]('Load more'))).toNotExist();
		await tapBack();
	});
});

const expectThreadMessages = async (message: string) => {
	await waitFor(element(by.id('room-view-title-thread 1')))
		.toExist()
		.withTimeout(10000);
	await waitFor(element(by[textMatcher](message)).atIndex(0))
		.toExist()
		.withTimeout(10000);
	await element(by[textMatcher](message)).atIndex(0).tap();
};

describe('Threads', () => {
	beforeAll(async () => {
		await device.launchApp({ permissions: { notifications: 'YES' }, newInstance: true });
	});

	it('should navigate to a thread from another room', async () => {
		if (device.getPlatform() === 'android') {
			return;
		}
		await navigateToRoom('jumping');
		await waitFor(element(by[textMatcher]("Go to jumping-thread's thread")).atIndex(0))
			.toExist()
			.withTimeout(5000);
		await jumpToQuotedMessage(element(by[textMatcher]("Go to jumping-thread's thread")).atIndex(0));
		await expectThreadMessages("Go to jumping-thread's thread");
		await tapBack();
	});

	it('should tap on thread message from main room', async () => {
		if (device.getPlatform() === 'android') {
			return;
		}
		await waitFor(element(by.id('room-view-title-jumping-thread')))
			.toExist()
			.withTimeout(5000);
		await waitFor(element(by[textMatcher]('thread message sent to main room')))
			.toExist()
			.withTimeout(10000);
		await element(by[textMatcher]('thread message sent to main room')).atIndex(0).tap();
		await expectThreadMessages('thread message sent to main room');
		await tapBack();
	});

	it('should tap on quote', async () => {
		if (device.getPlatform() === 'android') {
			return;
		}
		await waitFor(element(by.id('room-view-title-jumping-thread')))
			.toExist()
			.withTimeout(5000);
		await waitFor(element(by[textMatcher]('quoted')))
			.toExist()
			.withTimeout(5000);
		await jumpToQuotedMessage(element(by[textMatcher]('quoted')).atIndex(0));
		await expectThreadMessages('quoted');
		await tapBack();
	});

	it('should jump from search message', async () => {
		if (device.getPlatform() === 'android') {
			return;
		}
		await waitFor(element(by.id('room-view-title-jumping-thread')))
			.toExist()
			.withTimeout(5000);
		await element(by.id('room-view-search')).atIndex(0).tap();
		await waitFor(element(by.id('search-messages-view')))
			.toExist()
			.withTimeout(5000);
		await element(by.id('search-message-view-input')).replaceText('to be searched');
		await waitFor(element(by[textMatcher]('to be searched')).atIndex(getIndex()))
			.toExist()
			.withTimeout(30000);
		await element(by[textMatcher]('to be searched')).atIndex(getIndex()).tap();
		await expectThreadMessages('to be searched');
	});

	// TODO: Threads pagination
});
