/* eslint-disable no-restricted-globals */
import React from 'react';
import * as helpers from '../helpers';
import Globals from '../Globals';
import { Button, ButtonGroup, TextField, IconButton, Typography } from "@material-ui/core";
import gtag from 'ga-gtag';

import { ExpandIcon, SendMessageIcon } from '../icons';
import ChatMessage from './ChatMessage';
import NationAvatarGroup from './NationAvatarGroup';

export default class ChatChannel extends React.Component {
	constructor(props) {
		super(props);
		this.newAfter = Number.MAX_SAFE_INTEGER;
		this.renderBatchSize = 50;
		if (
			this.props.channel.Properties.NMessagesSince &&
			this.props.channel.Properties.NMessagesSince.Since
		) {
			this.newAfter = Date.parse(
				this.props.channel.Properties.NMessagesSince.Since
			);
		}
		this.state = { messages: [], numToRender: this.renderBatchSize };
		this.member = (this.props.game.Properties.Members || []).find((e) => {
			return e.User.Email === Globals.user.Email;
		});
		this.variant = Globals.variants.find((v) => {
			return v.Properties.Name === this.props.game.Properties.Variant;
		});
		this.abortController = new AbortController();
		this.sendMessage = this.sendMessage.bind(this);
		this.loadMessages = this.loadMessages.bind(this);
		this.phaseResolvedAfter = this.phaseResolvedAfter.bind(this);
		this.messageHandler = this.messageHandler.bind(this);
		this.updateHistoryAndSubscription = this.updateHistoryAndSubscription.bind(
			this
		);
		this.keyPress = this.keyPress.bind(this);
		this.scrollDown = this.scrollDown.bind(this);
		this.pollNewMessages = this.pollNewMessages.bind(this);
		this.autoExpandInput = this.autoExpandInput.bind(this);
		this.maybeRenderMore = this.maybeRenderMore.bind(this);
		this.messageSlice = this.messageSlice.bind(this);
	}
	messageSlice() {
		return this.state.messages.slice(-this.state.numToRender);
	}
	maybeRenderMore() {
		const scroller = document.getElementById("messages");
		if (
			scroller &&
			scroller.scrollTop < 2 * scroller.clientHeight &&
			this.state.numToRender < this.state.messages.length
		) {
			this.setState({
				numToRender: this.state.numToRender + this.renderBatchSize,
			});
		}
	}
	autoExpandInput() {
		const field = document.getElementById("chat-channel-input-field");
		field.style.height = "inherit";
		const computed = window.getComputedStyle(field);
		const height =
			parseInt(computed.getPropertyValue("border-top-width"), 10) +
			parseInt(computed.getPropertyValue("padding-top"), 10) +
			field.scrollHeight +
			parseInt(computed.getPropertyValue("padding-bottom"), 10) +
			parseInt(computed.getPropertyValue("border-bottom-width"), 10);
		field.style.height = height + "px";
		this.scrollDown();
	}
	messageHandler(payload) {
		if (payload.data.message.GameID !== this.props.game.Properties.ID) {
			return false;
		}
		if (
			payload.data.message.ChannelMembers.join(",") !==
			this.props.channel.Properties.Members.join(",")
		) {
			return false;
		}
		this.loadMessages(true);
		return true;
	}
	updateHistoryAndSubscription(
		isActive = this.props.isActive && this.props.channel
	) {
		if (isActive) {
			history.pushState(
				"",
				"",
				"/Game/" +
					this.props.game.Properties.ID +
					"/Channel/" +
					this.props.channel.Properties.Members.join(",") +
					"/Messages"
			);
			if (Globals.messaging.subscribe("message", this.messageHandler)) {
				console.log(
					"ChatChannel subscribing to `message` notifications."
				);
			}
			gtag("set", {
				page_title: "ChatChannel",
				page_location: location.href,
			});
			gtag("event", "page_view");
		} else {
			if (!this.props.parent.props.parent.dead) {
				history.pushState(
					"",
					"",
					"/Game/" + this.props.game.Properties.ID
				);
			}
			if (Globals.messaging.unsubscribe("message", this.messageHandler)) {
				console.log(
					"ChatChannel unsubscribing from `message` notifications."
				);
			}
		}
	}
	componentDidMount() {
		this.loadMessages().then(this.updateHistoryAndSubscription);
		helpers.onback(this.props.close);
		let scroller = document.getElementById("messages");
		if (scroller) {
			scroller.addEventListener("scroll", this.maybeRenderMore);
		}
	}
	componentDidUpdate(prevProps, prevState, snapshot) {
		this.updateHistoryAndSubscription();
		if (!prevProps.isActive && this.props.isActive) {
			this.loadMessages(true);
		}
	}
	componentWillUnmount() {
		this.abortController.abort();
		helpers.unback(this.props.close);
		this.updateHistoryAndSubscription(false);
		let scroller = document.getElementById("messages");
		if (scroller) {
			scroller.removeEventListener("scroll", this.maybeRenderMore);
		}
	}
	sendMessage() {
		if (!this.props.createMessageLink) {
			return;
		}
		const msg = document
			.getElementById("chat-channel-input-field")
			.value.trim();
		if (msg === "") {
			return;
		}
		this.setState(
			{
				messages: this.state.messages.concat([
					{
						Properties: {
							Sender: this.member.Nation,
							Body: msg,
							ID: Math.random(),
							CreatedAt: "" + new Date(),
						},
						undelivered: true,
					},
				]),
			},
			(_) => {
				document.getElementById("chat-channel-input-field").value = "";
				this.scrollDown();
				helpers
					.safeFetch(
						helpers.createRequest(
							this.props.createMessageLink.URL,
							{
								method: this.props.createMessageLink.Method,
								headers: {
									"Content-Type": "application/json",
								},
								body: JSON.stringify({
									Body: msg,
									ChannelMembers: this.props.channel
										.Properties.Members,
								}),
							}
						)
					)
					.then((resp) =>
						resp.json().then((js) => {
							gtag("event", "send_chat_message");
							if (
								!this.props.channel.Links.find((l) => {
									return l.Rel === "messages";
								})
							) {
								this.props.channel.Links.push({
									Rel: "messages",
									URL:
										"/Game/" +
										this.props.game.Properties.ID +
										"/Channel/" +
										js.Properties.ChannelMembers.join(",") +
										"/Messages",
									Method: "GET",
								});
							}
							if (Globals.messaging.tokenEnabled) {
								this.loadMessages(true);
							}
						})
					);
			}
		);
	}
	phaseResolvedAfter(phase, message) {
		if (phase.Properties.Resolved) {
			return (
				new Date(Date.parse(phase.Properties.ResolvedAt)).getTime() >
				new Date(Date.parse(message.Properties.CreatedAt)).getTime()
			);
		}
		return true;
	}
	keyPress(e) {
		if (e.key === "Enter" && e.ctrlKey) {
			e.stopPropagation();
			e.preventDefault();
			this.sendMessage(e);
		}
		this.autoExpandInput();
	}
	pollNewMessages() {
		const messagesLink = this.props.channel.Links.find((l) => {
			return l.Rel === "messages";
		});
		if (!messagesLink) {
			return;
		}
		let url = messagesLink.URL + "?wait=true";
		const newestPhase = this.props.phases[this.props.phases.length - 1];
		if (this.state.messages && this.state.messages.length > 0) {
			const newestMessage = this.state.messages[
				this.state.messages.length - 1
			];
			url += "&since=" + newestMessage.Properties.CreatedAt;
		}
		console.log("Initiating hanging request for new messages.");
		helpers
			.safeFetch(helpers.createRequest(url), {
				signal: this.abortController.signal,
			})
			.then((resp) => resp.json())
			.then((js) => {
				console.log("Got new message!");
				js.Properties.reverse();
				js.Properties.forEach((message) => {
					message.phase = newestPhase;
				});
				const newMessages = this.state.messages
					.filter((msg) => {
						return !msg.undelivered;
					})
					.concat(js.Properties);
				this.setState(
					{
						messages: newMessages,
					},
					(_) => {
						this.scrollDown();
						this.pollNewMessages();
					}
				);
			});
	}
	loadMessages(silent = false) {
		this.abortController.abort();
		this.abortController = new AbortController();
		const messagesLink = this.props.channel.Links.find((l) => {
			return l.Rel === "messages";
		});
		if (messagesLink) {
			if (!silent) {
				helpers.incProgress();
			}
			return helpers
				.safeFetch(helpers.createRequest(messagesLink.URL), {
					signal: this.abortController.signal,
				})
				.then((resp) => resp.json())
				.then((js) => {
					if (this.props.loaded) {
						this.props.loaded();
					}
					if (!silent) {
						helpers.decProgress();
					}
					js.Properties.reverse();
					let currentPhaseIdx = 0;
					js.Properties.forEach((message) => {
						while (
							currentPhaseIdx + 1 < this.props.phases.length &&
							!this.phaseResolvedAfter(
								this.props.phases[currentPhaseIdx],
								message
							)
						) {
							currentPhaseIdx++;
						}
						message.phase = this.props.phases[currentPhaseIdx];
					});
					this.setState({ messages: js.Properties }, this.scrollDown);
					if (!Globals.messaging.tokenEnabled) {
						this.pollNewMessages();
					}
					return Promise.resolve({});
				});
		} else {
			return Promise.resolve({});
		}
	}
	scrollDown() {
		const messagesEl = document.getElementById("messages");
		if (messagesEl) {
			messagesEl.scrollTop = messagesEl.scrollHeight;
		}
	}
	render() {
		if (this.props.channel) {
			return (
				<React.Fragment>
					<ButtonGroup
						orientation="vertical"
						style={{ width: "100%" }}
					>
						<Button
							onClick={this.props.close}
							style={{
								display: "flex",
								justifyContent: "space-between",
								borderTopLeftRadius: "0px",
								borderTopRightRadius: "0px",
								marginTop: "-1px",
							}}
						>
							<span style={{ display: "flex" }}>
								{this.variant.Properties.Nations.length ===
								this.props.channel.Properties.Members.length ? (
									<NationAvatarGroup
										game={this.props.game}
										newGameState={this.props.newGameState}
										gameState={this.props.gameState}
										variant={this.variant}
										nations={
											this.props.channel.Properties
												.Members
										}
									/>
								) : (
									<NationAvatarGroup
										game={this.props.game}
										newGameState={this.props.newGameState}
										gameState={this.props.gameState}
										variant={this.variant}
										nations={this.props.channel.Properties.Members.filter(
											(n) => {
												return (
													!this.member ||
													n !== this.member.Nation
												);
											}
										)}
									/>
								)}
							</span>

							{this.props.channel.Properties.Members.length >
							6 ? (
								<span
									style={{
										width: "calc(100% - 96px)",
										textAlign: "left",
										textTransform: "initial",
										lineHeight: "1.2",
									}}
								>
									{this.props.channel.Properties.Members
										.length ===
									this.variant.Properties.Nations.length
										? "Everyone"
										: this.props.channel.Properties.Members.filter(
												(n) => {
													return (
														!this.member ||
														n !== this.member.Nation
													);
												}
										  ).map((n, i) => {
												if (i === 0) {
													return n;
												} else {
													return ", " + n;
												}
										  })}
								</span>
							) : (
								<span
									style={{
										width: "calc(100% - 96px)",
										textAlign: "left",
										textTransform: "initial",
										lineHeight: "1.6",
									}}
								>
									{this.props.channel.Properties.Members
										.length ===
									this.variant.Properties.Nations.length
										? "Everyone"
										: this.props.channel.Properties.Members.filter(
												(n) => {
													return (
														!this.member ||
														n !== this.member.Nation
													);
												}
										  ).map((n, i) => {
												if (i === 0) {
													return n;
												} else {
													return ", " + n;
												}
										  })}
								</span>
							)}

							<ExpandIcon />
						</Button>
					</ButtonGroup>
					<div
						id="messages"
						style={{
							overflowY: "scroll",
							height: "calc(100% - 56px)",
							maxWidth: "962px",
							margin: "auto",
							width: "100%",
							overflowX: "hidden",
						}}
					>
						{this.messageSlice()
							.map((message, idx) => {
								const selfish =
									this.member &&
									this.member.Nation ===
										message.Properties.Sender;
								return (
									<React.Fragment key={message.Properties.ID}>
										{message.phase &&
										(idx === 0 ||
											message.phase.Properties
												.PhaseOrdinal !==
												this.messageSlice()[idx - 1]
													.phase.Properties
													.PhaseOrdinal) ? (
											<div
												style={{
													display: 'flex',
													alignItems: 'center',
													justifyContent: 'center',
												}}
											>
												<Typography
													color="primary"
													display="block"
													variant="subtitle2"
												>
													-------{" "}
													{helpers.phaseName(
														message.phase
													)}{" "}
													------
												</Typography>
											</div>
										) : (
											""
										)}
										{message.Properties.CreatedAt &&
										this.newAfter <
											Date.parse(
												message.Properties.CreatedAt
											) &&
										(idx === 0 ||
											this.newAfter >=
												Date.parse(
													this.messageSlice()[idx - 1]
														.Properties.CreatedAt
												)) ? (
											<div
												style={{
													justifyContent: 'center',
													width: '100%',
													maxWidth: '960px',
													display: 'flex',
													background: 'repeating-linear-gradient( 45deg, rgba(255,0,0,.1), rgba(255,0,0,0.1) 10px, rgba(255,0,0,0) 10px, rgba(255,0,0,0) 20px, rgba(0,0,255,0.1) 20px, rgba(0,0,255,0.1) 30px, rgba(255,255,255,0) 30px, rgba(255,255,255,0) 40px)',
												}}
											>
												<Typography
													variant="subtitle2"
													style={{ color: "#b71c1c" }}
													display="block"
												>
													New messages
												</Typography>
											</div>
										) : (
											""
										)}
										<ChatMessage
											game={this.props.game}
											onNewGameState={
												this.props.onNewGameState
											}
											gameState={this.props.gameState}
											key={message.Properties.ID}
											name={name}
											undelivered={message.undelivered}
											variant={this.variant}
											nation={message.Properties.Sender}
											text={message.Properties.Body}
											time={helpers.timeStrToDateTime(
												message.Properties.CreatedAt
											)}
											sender={selfish ? "self" : ""}
										/>
									</React.Fragment>
								);
							})}
						{this.props.createMessageLink &&
						!(this.props.channel.Properties.Members || []).find(
							(m) => {
								return m === helpers.DiplicitySender;
							}
						) ? (
							<div
								style={{
									display: "flex",
									flexDirection: "column",
									alignItems: "flex-end",
								}}
							>
								<div
									style={{
										display: "flex",
										alignItems: "flex-start",
										maxWidth: "960px",
										width: "calc(100% - 16px)",
										padding: "8px 8px 0px 8px",
										position: "sticky",
										bottom: "0px",
										backgroundColor: "white",
									}}
								>
									<TextField
										id="chat-channel-input-field"
										multiline
										rows="2"
										style={{ flexGrow: 100 }}
										className="chat-channel-input"
										label="Message"
										variant="outlined"
										onKeyDown={this.keyPress}
									/>
									<IconButton
										onClick={this.sendMessage}
										color="primary"
									>
										<SendMessageIcon />
									</IconButton>
								</div>
								<Typography
									id="desktopOnlyInput"
									style={{ marginRight: "56px" }}
									variant="caption"
								>
									Ctrl + Enter to send
								</Typography>
							</div>
						) : (
							""
						)}
					</div>
				</React.Fragment>
			);
		} else {
			return "";
		}
	}
}