import React, { Component } from "react";
import { View, TouchableOpacity, Image, StyleSheet } from "react-native";
import { Text } from "./Text";
import _ from "lodash";
import moment from "moment";
import { connect } from "react-redux";
import { Icon } from "@rneui/themed";
import {
	getPluralS,
	getThumb300,
	get1400,
	getSiteSettingFromState,
	getFirstName,
	getPluralOptions,
} from "../helper";
import {
	getMainBrandingColourFromState,
	TEXT_DARKEST,
	BG_GREY,
	TEXT_LIGHT,
	LINEGREY,
} from "../colours";
import { reactionActions, notificationActions } from "../apis";
import { blockUser, unblockUser } from "../actions";
import { ConfirmPopup } from "./ConfirmPopup";
import { ProfilePic } from "./ProfilePic";
import { ImagePopup } from "./ImagePopup";
import { InlineButton } from "./InlineButton";
import { Spinner } from "./Spinner";
import { Services } from "../config";

class CommentSection extends Component {
	constructor(props) {
		super(props);
		this.state = {
			commentsLoading: false,
			comments: [],
			addingComment: false,
			commentToDelete: null,
			commentToReport: null,
			commentReportedStatus: null,
			reportLoading: false,
			processing: false,
			muteExpiry: null,
			muteLoaded: false,
		};
	}

	componentDidMount() {
		this.getNotificationSate();

		if (!_.includes(this.props.user.hidden, "viewComment")) {
			this.getComments();
		}
	}

	componentWillUnmount() {
		if (this.loadTimer) {
			clearTimeout(this.loadTimer);
		}
	}

	onPressDeleteComment = (c) => {
		this.setState({ commentToDelete: c });
	};

	onPressConfirmDelete = () => {
		reactionActions.removeComment(this.state.commentToDelete.Id).then((res) => {
			console.log("deleted");
		});
		const newComments = _.filter(this.state.comments, (c) => {
			return c.Id !== this.state.commentToDelete.Id;
		});
		this.setState({
			comments: newComments,
			commentToDelete: null,
		});
	};

	onPressCancelDelete = () => {
		this.setState({ commentToDelete: null });
	};

	onPressReportComment = (c) => {
		this.setState({ commentToReport: c });
	};

	onPressBlockUser = (c) => {
		this.setState({ commentToBlock: c });
	};

	onPressConfirmBlock = () => {
		const userId = this.state.commentToBlock.UserId;
		this.props.blockUser(userId);
		this.setState({ commentToBlock: null });
	};

	onPressCancelBlock = () => {
		this.setState({ commentToBlock: null });
	};

	onPressUnblockUser = (c) => {
		this.setState({ commentToUnblock: c });
	};

	onPressConfirmUnblock = () => {
		const userId = this.state.commentToUnblock.UserId;
		this.props.unblockUser(userId);
		this.setState({ commentToUnblock: null });
	};

	onPressCancelUnblock = () => {
		this.setState({ commentToUnblock: null });
	};

	onPressConfirmReport = () => {
		const commentId = this.state.commentToReport.Id;
		this.setState({ reportLoading: true, commentToReport: null }, () => {
			reactionActions
				.reportComment(commentId)
				.then((res) => {
					this.setState({
						commentReportedStatus: "success",
						reportLoading: false,
					});
				})
				.catch((error) => {
					console.log("reportComment", error);
					this.setState({
						commentReportedStatus: "fail",
						reportLoading: false,
					});
				});
		});
	};

	onPressCancelReport = () => {
		this.setState({ commentToReport: null });
	};

	onPressConfirmReportStatus = () => {
		this.setState({ commentReportedStatus: null });
	};

	onPressCommentImage(image) {
		this.setState({
			imagePopupSource: [image],
			imagePopupOpen: true,
		});
	}

	onGoToAdd() {
		this.props.commentReply?.current?.focusInput();
	}

	onOpenThread = (comment) => {
		Services.navigation.navigate("thread", {
			...this.props,
			threadId: comment.Id,
		});
	};

	onMute = () => {
		const { entityType, entityId } = this.props;
		this.setState({ processing: true }, async () => {
			try {
				const { data } = await notificationActions.muteEntity(
					entityType,
					entityId,
				);
				// console.log('onMute', data);
				const muteExpiry = moment(data.Expiry);
				this.setState({ muteExpiry, processing: false });
			} catch (error) {
				console.error("onMute", error);
				this.setState({ processing: false });
			}
		});
	};

	onUnmute = () => {
		const { entityType, entityId } = this.props;
		this.setState({ processing: true }, async () => {
			try {
				const { data } = await notificationActions.unmuteEntity(
					entityType,
					entityId,
				);
				// console.log('onUnmute', data);
				this.setState({ muteExpiry: null, processing: false });
			} catch (error) {
				console.error("onUnmute", error);
				this.setState({ processing: false });
			}
		});
	};

	isMuted = () => {
		const { muteExpiry } = this.state;
		return muteExpiry && moment() <= muteExpiry;
	};

	getMuteRemaining = () => {
		const { muteExpiry } = this.state;
		const actual = muteExpiry
			? moment.duration(muteExpiry.diff(moment())).asHours()
			: 0;
		return Math.abs(Math.ceil(actual));
	};

	getNotificationSate = () => {
		const { processing } = this.state;
		const { entityType, entityId, notificationsForComments } = this.props;
		if (processing || !notificationsForComments) return;

		this.setState({ processing: true }, async () => {
			try {
				const { data } = await notificationActions.getEntityNotificationSetting(
					entityType,
					entityId,
				);
				// console.log('getNotificationSate', data);
				const muteExpiry = data ? moment(data.Expiry) : null;
				this.setState({ muteExpiry, muteLoaded: true, processing: false });
			} catch (error) {
				console.error("getNotificationSate", error);
				this.setState({ processing: false });
			}
		});
	};

	getAdjustedSize(size) {
		if (this.props.scaleFont) {
			return size + this.props.user.fontScale;
		}
		return size;
	}

	getComments() {
		if (!this.state.commentsLoadStarted) {
			this.setState({
				commentsLoadStarted: true,
				commentsLoading: true,
			});
			this.props.commentReply?.current?.loadingStarted();

			this.loadComments();
		}
	}

	isEmpty() {
		return _.isEmpty(this.state.comments);
	}

	loadComments() {
		const minTime = this.isEmpty()
			? 0
			: _.maxBy(this.state.comments, (c) => {
					return c.Timestamp;
				}).Timestamp;
		reactionActions
			.getComments(this.props.entityId, this.props.entityType, minTime)
			.then((res) => {
				this.setState(
					{
						comments: _.sortBy(
							_.uniqBy(
								_.filter(_.concat(this.state.comments, res.data), (c) => {
									if (!this.props.threadId) {
										return true;
									}
									return (
										c.Id === this.props.threadId ||
										c.ParentId === this.props.threadId
									);
								}),
								(c) => {
									return c.Id;
								},
							),
							"Timestamp",
						),
						commentsLoading: false,
					},
					() => {
						if (this.props.onCommentsLoaded) {
							this.props.onCommentsLoaded(this.state.comments.length);
						}
					},
				);
				//if (this.props.commentReply) {
				this.props.commentReply?.current?.loadingCompleted();
				//}
				if (this.props.live) {
					this.loadTimer = setTimeout(() => {
						this.loadComments();
					}, this.props.refreshFrequency || 2000);
				}
			})
			.catch((error) => {
				console.error("loadComments error", error);
				this.setState({ commentsLoading: false });
				this.props.commentReply?.current?.loadingCompleted();
			});
	}

	isLoading = () => {
		return this.state.commentsLoading;
	};

	startedAddingComment() {
		this.setState({
			addingComment: true,
		});
	}

	commentAdded(comment) {
		const newComments = this.state.comments;
		newComments.push(comment);
		this.setState(
			{
				addingComment: false,
				comments: newComments,
			},
			() => {
				if (this.props.onCommentAdded) {
					this.props.onCommentAdded();
				}
			},
		);
	}

	isUserBlocked = (c) => {
		return _.includes(this.props.blockedUsers, c.UserId);
	};

	canBlockComment = (c) => {
		return this.props.user.uid !== c.UserId;
	};

	canRemoveComment(c) {
		if (this.props.user.uid === c.UserId) {
			return true;
		}
		return _.includes(this.props.user.permissions, this.props.adminPermission);
	}

	closeCommentGallery() {
		this.setState({
			imagePopupSource: [],
			imagePopupOpen: false,
		});
	}

	renderCommentDeleteConfirm() {
		return (
			<ConfirmPopup
				visible={!!this.state.commentToDelete}
				onConfirm={this.onPressConfirmDelete}
				onCancel={this.onPressCancelDelete}
				onClose={this.onPressCancelDelete}
				text="Are you sure you want to delete this comment?"
			/>
		);
	}

	renderCommentReportConfirm() {
		return (
			<ConfirmPopup
				visible={!!this.state.commentToReport}
				onConfirm={this.onPressConfirmReport}
				onCancel={this.onPressCancelReport}
				onClose={this.onPressCancelReport}
				text="Are you sure you want to report this comment?"
				extraContent={
					<Text style={styles.commentReportText}>
						This comment will be reported to our team and considered for
						deletion
					</Text>
				}
			/>
		);
	}

	renderCommentBlockConfirm() {
		return (
			<ConfirmPopup
				visible={!!this.state.commentToBlock}
				onConfirm={this.onPressConfirmBlock}
				onCancel={this.onPressCancelBlock}
				onClose={this.onPressCancelBlock}
				text="Are you sure you want to block this user?"
				extraContent={
					<Text style={styles.commentReportText}>
						You will no longer see comments made by this user
					</Text>
				}
			/>
		);
	}

	renderCommentUnblockConfirm() {
		return (
			<ConfirmPopup
				visible={!!this.state.commentToUnblock}
				onConfirm={this.onPressConfirmUnblock}
				onCancel={this.onPressCancelUnblock}
				onClose={this.onPressCancelUnblock}
				text="Are you sure you want to unblock this user?"
				extraContent={
					<Text style={styles.commentReportText}>
						You will once again see comments made by this user
					</Text>
				}
			/>
		);
	}

	renderCommentReportStatus() {
		const { commentReportedStatus } = this.state;
		const isSuccess = commentReportedStatus === "success";
		return (
			<ConfirmPopup
				visible={!!commentReportedStatus}
				onConfirm={this.onPressConfirmReportStatus}
				text={isSuccess ? "Thank you for reporting" : "Unable to report"}
				extraContent={
					<Text style={styles.commentReportText}>
						{isSuccess
							? "We will review the comment within 24 hours"
							: "There was a problem reporting the comment please try again later"}
					</Text>
				}
				hideNo
				yesText={"Done"}
			/>
		);
	}

	renderCommentImage(c) {
		if (_.isEmpty(c.Image)) {
			return null;
		}
		return (
			<TouchableOpacity
				style={styles.commentImageContainer}
				onPress={this.onPressCommentImage.bind(this, get1400(c.Image))}
			>
				<Image
					style={styles.commentImage}
					source={{ uri: getThumb300(c.Image) }}
				/>
			</TouchableOpacity>
		);
	}

	renderReplyText = (c, isUserBlocked) => {
		if (this.props.threadId || this.props.hideReplyButton) {
			return null;
		}

		const threadComments = _.filter(this.state.comments, (innerC) => {
			return innerC.ParentId === c.Id;
		});

		let content = null;

		if (_.isEmpty(threadComments)) {
			// no replies
			content = (
				<Text
					style={[
						styles.commentRepliesText,
						{ color: this.props.colourBrandingMain },
					]}
				>{`Reply to ${getFirstName(
					!isUserBlocked && c.User ? c.User.displayName : "comment",
				)}`}</Text>
			);
		} else {
			// existing replies
			const profilePics = _.take(
				_.uniqBy(threadComments, (c) => c.UserId),
				3,
			);
			content = (
				<View style={styles.multiReplyContainer}>
					{profilePics.map((c, i) => {
						return (
							<ProfilePic
								key={c.Id}
								style={{ marginRight: -10 }}
								Diameter={20}
								ProfilePic={c.User?.profilePic}
							/>
						);
					})}
					<Text
						style={[
							styles.commentRepliesText,
							{ marginLeft: 20, color: this.props.colourBrandingMain },
						]}
					>{`${
						threadComments.length
					} repl${getPluralOptions(threadComments.length, "y", "ies")}`}</Text>
				</View>
			);
		}

		return (
			<View style={styles.commentReplies}>
				<TouchableOpacity
					onPress={() => {
						this.onOpenThread(c);
					}}
				>
					{content}
				</TouchableOpacity>
			</View>
		);
	};

	renderComment(c) {
		const isUserBlocked = this.isUserBlocked(c);
		return (
			<View style={styles.comment} key={c.Id}>
				<View style={styles.commentFlex}>
					<ProfilePic
						ProfilePic={isUserBlocked || !c.User ? null : c.User.profilePic}
						Diameter={40}
						style={styles.commentProfilePic}
					/>
					<View style={styles.commentBlock}>
						<View style={styles.commentTitleRow}>
							{this.canRemoveComment(c) ? (
								<TouchableOpacity
									onPress={this.onPressDeleteComment.bind(this, c)}
								>
									<View
										style={[
											styles.commentButtonContainer,
											{ backgroundColor: this.props.colourBrandingMain },
										]}
									>
										<Icon
											name="trash"
											type="font-awesome"
											iconStyle={styles.commentButtonIcon}
										/>
									</View>
								</TouchableOpacity>
							) : (
								!this.props.disableFlag && (
									<TouchableOpacity
										onPress={this.onPressReportComment.bind(this, c)}
									>
										<View
											style={[
												styles.commentButtonContainer,
												{ backgroundColor: this.props.colourBrandingMain },
											]}
										>
											<Icon
												name="flag"
												type="font-awesome"
												iconStyle={styles.commentButtonIcon}
											/>
										</View>
									</TouchableOpacity>
								)
							)}
							{!this.props.disableFlag &&
								this.canBlockComment(c) &&
								(isUserBlocked ? (
									<TouchableOpacity
										style={{ marginRight: 8 }}
										onPress={this.onPressUnblockUser.bind(this, c)}
									>
										<View
											style={[
												styles.commentButtonContainer,
												{ backgroundColor: this.props.colourBrandingMain },
											]}
										>
											<Icon
												name="user-plus"
												type="font-awesome"
												iconStyle={styles.commentButtonIcon}
											/>
										</View>
									</TouchableOpacity>
								) : (
									<TouchableOpacity
										style={{ marginRight: 8 }}
										onPress={this.onPressBlockUser.bind(this, c)}
									>
										<View
											style={[
												styles.commentButtonContainer,
												{ backgroundColor: this.props.colourBrandingMain },
											]}
										>
											<Icon
												name="user-times"
												type="font-awesome"
												iconStyle={styles.commentButtonIcon}
											/>
										</View>
									</TouchableOpacity>
								))}
							<Text
								style={[
									styles.commentName,
									{ fontSize: this.getAdjustedSize(13) },
								]}
							>
								{isUserBlocked
									? "[blocked user]"
									: c.User?.displayName || "Unknown User"}
							</Text>
						</View>
						{!_.isEmpty(c.Comment) && (
							<Text
								style={[
									styles.commentText,
									{ fontSize: this.getAdjustedSize(13) },
								]}
							>
								{isUserBlocked ? "[hidden]" : c.Comment}
							</Text>
						)}
						{!isUserBlocked && this.renderCommentImage(c)}
					</View>
				</View>
				<View style={styles.commentBottom}>
					<Text
						style={[styles.commentTime, { fontSize: this.getAdjustedSize(13) }]}
					>
						{moment.utc(c.Timestamp).local().format("D MMM • h:mma")}
					</Text>
					{this.renderReplyText(c, isUserBlocked)}
				</View>
			</View>
		);
	}

	renderMute() {
		const { notificationsForComments } = this.props;
		const { muteLoaded, muteExpiry, processing } = this.state;
		if (!notificationsForComments || !muteLoaded) return null;

		if (processing)
			return (
				<View style={styles.muteSpinnerContainer}>
					<Spinner size={"small"} color={this.props.colourBrandingMain} />
				</View>
			);

		const isMuted = this.isMuted();
		const hours = this.getMuteRemaining();
		const mutedFor = `Muted for ${hours} hour${getPluralS(hours)}`;
		// console.log(muteExpiry.format('DD MMM YYYY hh:mm a'));

		return (
			<View style={styles.muteContainer}>
				{isMuted && muteExpiry ? (
					<Text
						style={[
							{ color: this.props.colourBrandingMain },
							styles.mutedForText,
						]}
					>
						{mutedFor}
					</Text>
				) : null}
				<InlineButton
					onPress={isMuted ? this.onUnmute : this.onMute}
					color="#fff"
					style={[
						{ borderColor: this.props.colourBrandingMain },
						styles.muteButton,
					]}
					disabled={processing}
					disabledOpacity
					noText
				>
					<View style={styles.muteButtonInner}>
						<Icon
							name={isMuted ? "bell-o" : "bell-slash-o"}
							type={"font-awesome"}
							iconStyle={[
								{ color: this.props.colourBrandingMain },
								styles.muteButtonIcon,
							]}
						/>
						<Text
							style={[
								{ color: this.props.colourBrandingMain },
								styles.muteButtonText,
							]}
						>
							{isMuted ? "Unmute" : "Mute"}
						</Text>
					</View>
				</InlineButton>
			</View>
		);
	}

	renderComments() {
		if (this.state.commentsLoading) {
			return (
				<View style={styles.commentSection}>
					<Spinner color={this.props.colourBrandingMain} />
				</View>
			);
		}
		if (this.isEmpty() && !this.state.addingComment) {
			if (_.includes(this.props.user.hidden, "addComment")) {
				return null;
			}
			if (!_.isNil(this.props.placeHolder) && _.isEmpty(this.props.placeHolder))
				return null;
			return (
				<View style={styles.commentSection}>
					<Text
						style={[
							styles.commentsEmpty,
							{ fontSize: this.getAdjustedSize(15) },
						]}
					>
						{_.isNil(this.props.placeHolder)
							? "Be the first to add a comment!"
							: this.props.placeHolder}
					</Text>
				</View>
			);
		}
		let source = [...this.state.comments];
		if (this.props.reverseOrder) {
			source = source.reverse();
		}
		if (!this.props.showReplies && !this.props.threadId) {
			source = _.filter(source, (c) => {
				return !c.ParentId;
			});
		}
		return (
			<View style={styles.commentSection}>
				{!this.isEmpty() && (
					<View style={styles.commentSectionTitleRow}>
						<View style={{ alignItems: "flex-end" }}>
							{this.renderMute()}
							{!this.props.hideAddComment && this.state.comments.length > 2 && (
								<TouchableOpacity onPress={this.onGoToAdd.bind(this)}>
									<Text
										style={[
											styles.goToText,
											{ color: this.props.colourBrandingMain },
										]}
									>
										Add a comment
									</Text>
								</TouchableOpacity>
							)}
						</View>
						<Text
							style={[
								styles.commentCount,
								{ fontSize: this.getAdjustedSize(15) },
							]}
						>
							{this.state.comments.length}
							{` comment${getPluralS(this.state.comments.length)}`}
						</Text>
					</View>
				)}
				{this.props.reverseOrder && this.state.addingComment && (
					<Spinner color={this.props.colourBrandingMain} />
				)}
				{source.map((c) => {
					return this.renderComment(c);
				})}
				{!this.props.reverseOrder && this.state.addingComment && (
					<Spinner color={this.props.colourBrandingMain} />
				)}
			</View>
		);
	}

	renderCommentImagePopup() {
		return (
			<ImagePopup
				visible={this.state.imagePopupOpen}
				images={this.state.imagePopupSource}
				onClose={this.closeCommentGallery.bind(this)}
			/>
		);
	}

	renderReportLoading() {
		if (!this.state.reportLoading) return null;
		return (
			<View style={styles.reportLoadingContainer}>
				<Spinner color={this.props.colourBrandingMain} />
			</View>
		);
	}

	render() {
		if (_.includes(this.props.user.hidden, "viewComment")) {
			return null;
		}
		return (
			<View style={[styles.commentSectionOuter, this.props.style]}>
				{this.renderComments()}
				{this.renderReportLoading()}
				{this.renderCommentDeleteConfirm()}
				{this.renderCommentReportConfirm()}
				{this.renderCommentBlockConfirm()}
				{this.renderCommentUnblockConfirm()}
				{this.renderCommentReportStatus()}
				{this.renderCommentImagePopup()}
			</View>
		);
	}
}

const styles = StyleSheet.create({
	commentSectionOuter: {
		flex: 1,
		paddingHorizontal: 16,
	},
	commentSection: {
		flex: 1,
		paddingVertical: 12,
		borderTopColor: LINEGREY,
		borderTopWidth: 1,
	},
	commentCount: {
		fontFamily: "sf-semibold",
		color: TEXT_DARKEST,
		flex: 1,
		marginTop: 4,
	},
	comment: {
		marginTop: 16,
	},
	commentFlex: {
		flexDirection: "row",
	},
	commentProfilePic: {
		marginRight: 8,
	},
	commentBlock: {
		flex: 1,
		backgroundColor: BG_GREY,
		borderRadius: 5,
		padding: 8,
	},
	commentTitleRow: {
		flexDirection: "row-reverse",
		alignItems: "center",
	},
	commentButtonContainer: {
		width: 24,
		height: 24,
		borderRadius: 12,
		alignItems: "center",
		justifyContent: "center",
	},
	commentButtonIcon: {
		fontSize: 13,
		color: "#fff",
	},
	commentName: {
		fontFamily: "sf-semibold",
		color: TEXT_DARKEST,
		flex: 1,
	},
	commentText: {
		marginTop: 8,
		fontFamily: "sf-regular",
		color: TEXT_DARKEST,
	},
	commentBottom: {
		flexDirection: "row-reverse",
		justifyContent: "space-between",
		alignItems: "center",
	},
	commentTime: {
		fontFamily: "sf-regular",
		marginTop: 4,
		color: TEXT_LIGHT,
		textAlign: "right",
	},
	commentReplies: {
		flex: 1,
		paddingLeft: 48,
	},
	commentRepliesText: {
		fontFamily: "sf-semibold",
		fontSize: 15,
	},
	multiReplyContainer: {
		flexDirection: "row",
		alignItems: "center",
		paddingVertical: 4,
	},
	commentImageContainer: {
		marginTop: 8,
		width: 60,
		height: 60,
	},
	commentImage: {
		width: 60,
		height: 60,
		borderRadius: 2,
	},
	commentsEmpty: {
		fontFamily: "sf-semibold",
		color: TEXT_DARKEST,
	},
	commentSectionTitleRow: {
		flexDirection: "row-reverse",
	},
	commentReportText: {
		fontFamily: "sf-regular",
		fontSize: 14,
		paddingHorizontal: 22,
		textAlign: "center",
	},
	reportLoadingContainer: {
		paddingVertical: 10,
	},
	goToText: {
		marginTop: 4,
	},
	muteSpinnerContainer: {
		width: 100,
		marginBottom: 6,
	},
	muteContainer: {
		flexDirection: "row",
		alignItems: "center",
		justifyContent: "flex-end",
		marginBottom: 6,
	},
	mutedForText: {
		fontFamily: "sf-semibold",
		fontSize: 13,
		marginRight: 8,
	},
	muteButton: {
		borderWidth: 1,
		paddingHorizontal: 8,
	},
	muteButtonInner: {
		flexDirection: "row",
		alignItems: "center",
	},
	muteButtonIcon: {
		fontSize: 14,
	},
	muteButtonText: {
		fontFamily: "sf-semibold",
		fontSize: 14,
		marginLeft: 6,
	},
});

const mapStateToProps = (state) => {
	return {
		colourBrandingMain: getMainBrandingColourFromState(state),
		user: state.user,
		notificationsForComments: getSiteSettingFromState(
			state,
			"NotificationsForComments",
			false,
		),
		blockedUsers: state.userSettings.blockedUsers || [],
	};
};

const commentSection = connect(
	mapStateToProps,
	{ blockUser, unblockUser },
	null,
	{ forwardRef: true },
)(CommentSection);
export { commentSection as CommentSection };
