import React, { forwardRef, useState, useRef } from 'react';
import {
	View,
	TouchableOpacity,
	Dimensions,
	StyleSheet,
	Platform,
} from 'react-native';
import _ from 'lodash';
import PropTypes from 'prop-types';
import {
	ActionSheet,
	Text,
	TableCellPlaylist,
	RadioIcon,
} from 'nixplay-ui-kit';
import Animated, { Easing } from 'react-native-reanimated';
import { BlurView } from '@react-native-community/blur';
import i18n from '~/locale/i18n';
import CTAHeader from '~comp/CTAHeader';
import PlaylistTypeLabel from '~comp/playlistTypeLabel';
import RedDot from '~comp/redDot';
import { color } from '~/styles/variables';

const { height } = Dimensions.get('window');
const actionSheetMaxHeight = height * 0.67;
const isiOS = Platform.OS === 'ios';

const styles = StyleSheet.create({
	actionSheet: {
		maxHeight: actionSheetMaxHeight,
	},
	actionSheetTitle: {
		textAlign: 'center',
		paddingVertical: 24,
	},
	actionSheetItem: {
		paddingHorizontal: 16,
	},
	noHorizontalPadding: {
		paddingHorizontal: 0,
	},
	plusPlanRadio: {
		alignSelf: 'center',
		marginLeft: 2,
		marginRight: 12,
	},
	playAllTextStyle: {
		alignSelf: 'center',
		fontSize: 17,
		lineHeight: 22,
		letterSpacing: 0.408,
		color: '#466A78',
		textAlign: 'left',
	},
	selectFramesContainer: {
		flexDirection: 'row',
		justifyContent: 'center',
		paddingHorizontal: 16,
	},
	ctaHeader: {
		margin: 0,
		height: 60,
		width: '80%',
		marginVertical: 8,
		backgroundColor: color.translucentBg,
		flex: 1,
	},
	innerCTAButton: {
		marginLeft: 0,
	},
	newPlaylistButton: {
		left: 0,
	},
	wideButton: {
		width: Dimensions.get('window').width,
		paddingHorizontal: 16,
	},
	assignPlaylistButton: {
		right: 0,
	},
	floatingHeader: {
		position: 'absolute',
		top: (isiOS) ? 75 : 70,
		alignSelf: 'center',
		width: '100%',
	},
	translucentBg: {
		backgroundColor: (isiOS) ? color.translucentBg : 'rgba(250, 250, 250, 0.8)',
	},
	hiddenHeader: {
		width: 10,
	},
	label: {
		right: 5,
	},
	dynamicLabel: {
		left: 5,
	},
	blur: {
		position: 'absolute',
		top: 0,
		bottom: 0,
		left: 0,
		right: 0,
	},
});

// CUSTOM REACT HOOK: useFade
// This hook holds the scroll position (scrollY); see: https://reactjs.org/docs/hooks-reference.html#useref
// It also interpolates opacity to be between 0 and 1, and changes zIndex accordingly
// Use them in tandem with an Animated component
const useFade = () => {
	// The range [0, 100] defines the length of scroll for the fade out animation to complete
	const MIN_SCROLL = 0;
	const MAX_SCROLL = 100;

	// scrollY will be attached to the value of the scrollbar in the ScrollView component
	// min- and max- scrollRange variables are the animatable bounds of interpolation
	// clamp determines the visible animatable properties (opacity, zIndex)
	const scrollY = useRef(new Animated.Value(0)).current;
	const minScrollRange = useRef(new Animated.Value(MIN_SCROLL)).current;
	const maxScrollRange = useRef(new Animated.Value(MAX_SCROLL)).current;
	const clamp = Animated.diffClamp(scrollY, Animated.max(1, scrollY), maxScrollRange);

	// the input range for all interpolations always range from min- and max- scrollRange
	const inputRange = [minScrollRange, maxScrollRange];

	// interpolate the clamp from the input range into values from 1 to 0
	// this lets opacity decrease as the user scrolls down, and vice versa
	const opacityButtons = Animated.interpolate(clamp, {
		inputRange,
		outputRange: [1, 0],
		extrapolateLeft: 'identity',
		extrapolateRight: 'clamp',
	});

	// interpolate the clamp from the input range into values from 0 to 1
	// this lets the ScrollView quickly move forward as opacity decreases
	const zIndexScrollView = Animated.interpolate(clamp, {
		inputRange,
		outputRange: [0, 1],
		extrapolate: 'clamp',
	});

	// interpolate the clamp from the input range into values from 7 to 0
	// this lets the button headers slowly move backward as opacity decreases
	const zIndexButtons = Animated.interpolate(clamp, {
		inputRange,
		outputRange: [7, 0],
		extrapolate: 'clamp',
	});

	// call this when we need to make the header visible
	// when offset is `undefined`, it snaps the values to the default with no animation
	// otherwise, it animates the headers as specified in: https://www.wrike.com/open.htm?id=422801675
	const fadeInHeader = (offset, duration = 500) => {
		if (offset !== undefined) {
			Animated.timing(minScrollRange, {
				toValue: new Animated.Value(offset),
				duration,
				easing: Easing.inOut(Easing.ease),
			}).start();
			Animated.timing(maxScrollRange, {
				toValue: Animated.add(offset, MAX_SCROLL),
				duration,
				easing: Easing.inOut(Easing.ease),
			}).start();
		} else {
			// this exact order is important
			// do not change the order
			minScrollRange.setValue(MIN_SCROLL);
			maxScrollRange.setValue(MAX_SCROLL);
			scrollY.setValue(0);
		}
	};

	return [scrollY, opacityButtons, zIndexButtons, zIndexScrollView, fadeInHeader];
};

const renderOneButton = (
	scrollY,
	selectPlaylistActionSheet,
	createPlaylistActionSheet,
	openPlaylistAssignment,
	resetAllPlaylistIdsWhenClosed,
) => (
	<CTAHeader
		style={[styles.ctaHeader, styles.newPlaylistButton, styles.wideButton]}
		title={i18n.t('playlists.newPlaylist')}
		onPress={() => {
			selectPlaylistActionSheet.close();
			createPlaylistActionSheet.openCreatePlaylistActionSheet();
			resetAllPlaylistIdsWhenClosed();
		}}
		textSize={14}
	/>
);

const renderTwoButtons = (
	scrollY,
	selectPlaylistActionSheet,
	createPlaylistActionSheet,
	openPlaylistAssignment,
	resetAllPlaylistIdsWhenClosed,
) => (
	<React.Fragment>
		<CTAHeader
			style={[styles.ctaHeader, styles.newPlaylistButton]}
			title={i18n.t('playlists.newPlaylist')}
			onPress={() => {
				selectPlaylistActionSheet.close();
				createPlaylistActionSheet.openCreatePlaylistActionSheet();
				resetAllPlaylistIdsWhenClosed();
			}}
			textSize={14}
		/>
		<View style={{ width: 16, height: 44 }} />
		<CTAHeader
			style={[styles.ctaHeader, styles.assignPlaylistButton]}
			title={i18n.t('playlists.assignPlaylists')}
			onPress={() => {
				openPlaylistAssignment(true);
				resetAllPlaylistIdsWhenClosed();
			}}
			textSize={14}
			iconHidden
			innerButtonStyle={styles.innerCTAButton}
			innerButtonProps={{
				numberOfLines: 1,
				ellipsizeMode: 'tail',
			}}
		/>
	</React.Fragment>
);

const renderPlayAllPlaylistsOption = (
	scrollY,
	thisActionSheet,
	currentFrame,
	changeCurrentPlaylist,
	currentFramePlaylists,
	allNewCreatedPlaylistIds,
	resetAllPlaylistIdsWhenClosed,
) => (
	<TouchableOpacity
		style={styles.actionSheetItem}
		onPress={() => {
			changeCurrentPlaylist(-1);
			thisActionSheet.close();
			resetAllPlaylistIdsWhenClosed();
		}}
	>
		<View style={{ flexDirection: 'row', paddingVertical: 14 }}>
			<RadioIcon
				style={styles.plusPlanRadio}
				active={(currentFrame.slideshow === -1)}
			/>
			<Text style={styles.playAllTextStyle}>
				{i18n.t('playlists.playAllPlaylistsBelow')}
			</Text>
		</View>
	</TouchableOpacity>
);

const renderPlayOnePlaylistOption = (
	scrollY,
	thisActionSheet,
	currentFrame,
	changeCurrentPlaylist,
	currentFramePlaylists,
	allNewCreatedPlaylistIds,
	resetAllPlaylistIdsWhenClosed,
) => (playlist) => (
	<TouchableOpacity
		style={styles.actionSheetItem}
		key={playlist.id}
		onPress={() => {
			changeCurrentPlaylist(playlist.id);
			thisActionSheet.close();
			resetAllPlaylistIdsWhenClosed();
		}}
	>
		<View style={{ flexDirection: 'row' }}>
			{currentFramePlaylists.length > 1 && (
				<RadioIcon
					style={styles.plusPlanRadio}
					active={playlist.id === currentFrame.slideshow}
				/>
			)}
			<TableCellPlaylist
				playlist={playlist}
				renderRedDot={(leftOffset = 70) => allNewCreatedPlaylistIds.indexOf(playlist.id) > -1 &&
					<RedDot scale={0.8} style={{ marginLeft: leftOffset - 15, marginTop: 3 }} />
				}
				dynamicPlaylistLabel={() => _.isEqual(playlist.type, 'google') &&
					<PlaylistTypeLabel type="googlePhotos" containerStyle={styles.dynamicLabel} />
				}
				style={{
					width: currentFramePlaylists.length > 1 ?
						(Dimensions.get('window').width * 0.86) : (Dimensions.get('window').width - 38),
				}}
			/>
		</View>
	</TouchableOpacity>
);

const renderCancelButton = (OS, resetAllPlaylistIdsWhenClosed) => (
	<ActionSheet.Cancel
		hideButton={OS === 'android'}
		onPress={resetAllPlaylistIdsWhenClosed}
	>
		{i18n.t('common.cancel')}
	</ActionSheet.Cancel>
);

const HomePlaylistPicker = forwardRef((props, ref) => {
	const {
		// Props
		playlists,
		currentFrame,
		currentFramePlaylists,
		allNewCreatedPlaylistIds,
		// Methods
		openPlaylistAssignment,
		changeCurrentPlaylist,
		resetAllPlaylistIdsWhenClosed,
		// Refs
		createPlaylistActionSheet,
	} = props;

	const [scrollviewHeight, useScrollviewHeight] = useState(0);
	const [thisActionSheet, setThisActionSheet] = useState({ close: () => {} });
	const [selectPlaylistActionSheet, setSelectPlaylistActionSheet] = useState({ close: () => {} });
	const [scrollY, opacityButtons, zIndexButtons, zIndexScrollView, fadeInHeader] = useFade();

	const buttonDependencies = [
		scrollY,
		selectPlaylistActionSheet,
		createPlaylistActionSheet,
		openPlaylistAssignment,
		resetAllPlaylistIdsWhenClosed,
	];
	const radioOptionsDependencies = [
		scrollY,
		thisActionSheet,
		currentFrame,
		changeCurrentPlaylist,
		currentFramePlaylists,
		allNewCreatedPlaylistIds,
		resetAllPlaylistIdsWhenClosed,
	];
	const cancelDependencies = [
		Platform.OS,
		resetAllPlaylistIdsWhenClosed,
	];

	return (
		<ActionSheet
			ref={(actionSheet) => {
				setThisActionSheet(actionSheet);
				setSelectPlaylistActionSheet(actionSheet);
				ref(actionSheet, fadeInHeader);
			}}
		>
			<ActionSheet.Custom
				borderTop={false}
				style={styles.noHorizontalPadding}
			>
				<Text style={styles.actionSheetTitle} textStyle="title2">{i18n.t('frames.frameContents')}</Text>
				<Animated.ScrollView
					style={[styles.actionSheet, { zIndex: zIndexScrollView }]}
					onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }])}
					onMomentumScrollEnd={(event) => { fadeInHeader(event.nativeEvent.contentOffset.y); }}
					onScrollEndDrag={(event) => { fadeInHeader(event.nativeEvent.contentOffset.y); }}
					scrollEventThrottle={16}
					bounces={false}
					decelerationRate="fast"
					onLayout={(event) => { useScrollviewHeight(event.nativeEvent.layout.height); }}
					showsVerticalScrollIndicator={false}
				>
					<View style={[styles.ctaHeader, styles.hiddenHeader]} />
					{ currentFramePlaylists.length > 1 && renderPlayAllPlaylistsOption(...radioOptionsDependencies) }
					{ currentFramePlaylists.map(renderPlayOnePlaylistOption(...radioOptionsDependencies)) }
				</Animated.ScrollView>
				<Animated.View
					style={[
						styles.selectFramesContainer,
						styles.floatingHeader,
						...(scrollviewHeight + 5 >= actionSheetMaxHeight ? styles.translucentBg : {}),
						{ opacity: opacityButtons },
						{ zIndex: zIndexButtons },
					]}
				>
					{ isiOS && (<BlurView
						style={styles.blur}
						blurType="light"
						blurAmount={7}
					/>)}
					{ playlists.length <= 1 ? renderOneButton(...buttonDependencies) : renderTwoButtons(...buttonDependencies) }
				</Animated.View>
			</ActionSheet.Custom>
			{ renderCancelButton(...cancelDependencies) }
		</ActionSheet>
	);
});

HomePlaylistPicker.propTypes = {
	playlists: PropTypes.array.isRequired,
	currentFrame: PropTypes.object.isRequired,
	currentFramePlaylists: PropTypes.array.isRequired,
	openPlaylistAssignment: PropTypes.func.isRequired,
	changeCurrentPlaylist: PropTypes.func.isRequired,
	createPlaylistActionSheet: PropTypes.object,
	allNewCreatedPlaylistIds: PropTypes.array,
	resetAllPlaylistIdsWhenClosed: PropTypes.func,
};

HomePlaylistPicker.defaultProps = {
	createPlaylistActionSheet: {},
	allNewCreatedPlaylistIds: [],
	resetAllPlaylistIdsWhenClosed: () => {},
};

export default HomePlaylistPicker;
