/* eslint no-use-before-define: ["error", { "variables": false }], react-native/no-inline-styles: 0 */

// NOTE:
// This is a modified version of react-native-gifted-chat Message component

// Original source:
// https://github.com/FaridSafi/react-native-gifted-chat/blob/master/src/Message.js

import PropTypes from "prop-types";
import React from "react";
import { View, StyleSheet, TouchableOpacity } from "react-native";
import { ViewPropTypes } from "deprecated-react-native-prop-types";
import _ from "lodash";

import {
	Avatar,
	Bubble,
	SystemMessage,
	Day,
	utils,
} from "react-native-gifted-chat";
import { TEXT_MID, TEXT_LIGHT, TEXT_DARK, TEXT_SUPER_LIGHT } from "../colours";
import { getFirstName } from "../helper";
import { Text } from ".";

const isSameUser = utils.isSameUser;
const isSameDay = utils.isSameDay;

export default class PlussChatMessage extends React.Component {
	getInnerComponentProps() {
		const { containerStyle, ...props } = this.props;
		return {
			...props,
			isSameUser,
			isSameDay,
		};
	}

	isCurrentUser() {
		if (this.props.user._id === this.props.currentMessage.user._id) {
			return true;
		}
		return false;
	}

	renderDay() {
		if (this.props.currentMessage.createdAt) {
			const dayProps = this.getInnerComponentProps();
			if (this.props.renderDay) {
				return this.props.renderDay(dayProps);
			}
			return <Day {...dayProps} />;
		}
		return null;
	}

	renderBubble() {
		const bubbleProps = this.getInnerComponentProps();
		if (this.props.renderBubble) {
			return this.props.renderBubble(bubbleProps);
		}
		return <Bubble {...bubbleProps} />;
	}

	renderSystemMessage() {
		const systemMessageProps = this.getInnerComponentProps();
		if (this.props.renderSystemMessage) {
			return this.props.renderSystemMessage(systemMessageProps);
		}
		return <SystemMessage {...systemMessageProps} />;
	}

	renderAvatar() {
		if (this.isCurrentUser() && !this.props.showUserAvatar) {
			return null;
		}
		const avatarProps = this.getInnerComponentProps();
		const { currentMessage } = avatarProps;
		if (
			currentMessage.user.avatar === null ||
			_.isEmpty(currentMessage.user.avatar)
		) {
			return null;
		}
		return (
			<Avatar
				{...avatarProps}
				imageStyle={{
					left: {
						width: 30,
						height: 30,
						borderRadius: 15,
					},
					right: {
						width: 30,
						height: 30,
						borderRadius: 15,
					},
				}}
				containerStyle={{
					left: {
						marginRight: 10,
					},
					right: {
						marginLeft: 10,
					},
				}}
			/>
		);
	}

	renderName() {
		const nameProps = this.getInnerComponentProps();
		const { currentMessage } = nameProps;
		if (currentMessage.user.name === null) {
			return null;
		}
		let nameText = this.isCurrentUser()
			? "Me"
			: getFirstName(currentMessage.user.name);
		if (
			this.props.currentMessage &&
			this.props.currentMessage.replyingTo &&
			this.props.currentMessage.replyingTo.user &&
			!_.isEmpty(this.props.currentMessage.replyingTo.user.name)
		) {
			nameText = `${nameText} replying to ${this.props.currentMessage.replyingTo.user.name}`;
		}
		return <Text style={[styles[this.props.position].name]}>{nameText}</Text>;
	}

	renderReply() {
		// Don't show reply quote for deleted messages
		if (
			!this.props.currentMessage ||
			!this.props.currentMessage.replyingTo ||
			this.props.currentMessage.deleted
		) {
			return null;
		}
		return (
			<View style={styles[this.props.position].replyBubble}>
				<View style={styles[this.props.position].replyBubbleInner}>
					<Text style={styles[this.props.position].replyBubbleText}>
						{(this.props.currentMessage.replyingTo.text || "").substr(0, 100)}
					</Text>
				</View>
			</View>
		);
	}

	renderReplyButton() {
		// Don't show reply button for deleted messages
		if (this.props.currentMessage.deleted) {
			return null;
		}
		return (
			<TouchableOpacity
				style={styles[this.props.position].replyContainer}
				onPress={this.props.onPressReply}
			>
				<Text type="button" style={{ color: this.props.colourBrandingMain }}>
					Reply
				</Text>
			</TouchableOpacity>
		);
	}

	renderDeleteButton() {
		// Only show delete button if handler is provided and for current user's messages that aren't already deleted
		if (
			!this.props.onPressDelete ||
			!this.isCurrentUser() ||
			this.props.currentMessage.deleted
		) {
			return null;
		}
		return (
			<TouchableOpacity
				style={styles[this.props.position].deleteContainer}
				onPress={this.props.onPressDelete}
			>
				<Text type="button" style={{ color: this.props.colourBrandingMain }}>
					Delete
				</Text>
			</TouchableOpacity>
		);
	}

	render() {
		const sameUserAsLast = isSameUser(
			this.props.currentMessage,
			this.props.previousMessage,
		);
		const sameUser = isSameUser(
			this.props.currentMessage,
			this.props.nextMessage,
		);
		return (
			<View>
				{this.renderDay()}
				{this.props.currentMessage.system ? (
					this.renderSystemMessage()
				) : (
					<View>
						{sameUserAsLast ? null : this.renderName()}
						<View
							style={[
								styles[this.props.position].container,
								{ marginBottom: sameUser ? 2 : 10 },
								!this.props.inverted && { marginBottom: 2 },
								this.props.containerStyle[this.props.position],
							]}
						>
							{this.props.position === "left" ? this.renderAvatar() : null}
							<View>
								{this.renderReply()}
								{this.renderBubble()}
								<View style={styles[this.props.position].actionButtons}>
									{this.renderReplyButton()}
									{this.renderDeleteButton()}
								</View>
							</View>
							{this.props.position === "right" ? this.renderAvatar() : null}
						</View>
					</View>
				)}
			</View>
		);
	}
}

const styles = {
	left: StyleSheet.create({
		container: {
			flexDirection: "row",
			alignItems: "flex-end",
			justifyContent: "flex-start",
			marginLeft: 10,
			marginRight: 0,
		},
		name: {
			fontFamily: "sf-regular",
			color: TEXT_LIGHT,
			fontSize: 14,
			textAlign: "left",
			marginLeft: 50,
			marginBottom: 5,
		},
		replyBubble: {
			flexDirection: "row",
			alignItems: "flex-end",
			justifyContent: "flex-start",
			paddingLeft: 20,
		},
		replyBubbleInner: {
			padding: 4,
			paddingBottom: 16,
			marginBottom: -12,
			borderRadius: 4,
			opacity: 0.7,
			backgroundColor: TEXT_SUPER_LIGHT,
		},
		replyBubbleText: {
			fontFamily: "sf-regular",
			color: TEXT_DARK,
			fontSize: 13,
			textAlign: "left",
		},
		replyContainer: {
			paddingLeft: 20,
			paddingRight: 10,
		},
		deleteContainer: {
			paddingLeft: 10,
		},
		actionButtons: {
			flexDirection: "row",
			alignItems: "center",
		},
	}),
	right: StyleSheet.create({
		container: {
			flexDirection: "row",
			alignItems: "flex-end",
			justifyContent: "flex-end",
			marginLeft: 0,
			marginRight: 10,
		},
		name: {
			fontFamily: "sf-regular",
			color: TEXT_LIGHT,
			fontSize: 14,
			textAlign: "right",
			marginRight: 10,
			marginBottom: 5,
		},
		replyBubble: {
			flexDirection: "row",
			alignItems: "flex-end",
			justifyContent: "flex-end",
			paddingRight: 10,
		},
		replyBubbleInner: {
			padding: 4,
			paddingBottom: 16,
			marginBottom: -12,
			borderRadius: 4,
			opacity: 0.7,
			backgroundColor: TEXT_SUPER_LIGHT,
		},
		replyBubbleText: {
			fontFamily: "sf-regular",
			color: TEXT_DARK,
			fontSize: 13,
			textAlign: "right",
		},
		replyContainer: {
			paddingRight: 10,
		},
		deleteContainer: {
			paddingRight: 10,
		},
		actionButtons: {
			flexDirection: "row",
			alignItems: "center",
			alignSelf: "flex-end",
		},
	}),
};

PlussChatMessage.defaultProps = {
	renderAvatar: undefined,
	renderBubble: null,
	renderDay: null,
	renderSystemMessage: null,
	position: "left",
	currentMessage: {},
	nextMessage: {},
	previousMessage: {},
	user: {},
	containerStyle: {},
	showUserAvatar: true,
	inverted: true,
};

PlussChatMessage.propTypes = {
	renderAvatar: PropTypes.func,
	showUserAvatar: PropTypes.bool,
	renderBubble: PropTypes.func,
	renderDay: PropTypes.func,
	renderSystemMessage: PropTypes.func,
	position: PropTypes.oneOf(["left", "right"]),
	currentMessage: PropTypes.object,
	nextMessage: PropTypes.object,
	previousMessage: PropTypes.object,
	user: PropTypes.object,
	inverted: PropTypes.bool,
	containerStyle: PropTypes.shape({
		left: ViewPropTypes.style,
		right: ViewPropTypes.style,
	}),
};
