import React, { Component } from 'react';
import { Helmet } from 'react-helmet';
import { Header, Image, Divider, Grid, Segment, Rating, Dropdown, Popup, Label, Button, Comment } from 'semantic-ui-react';
import { graphql, navigate } from 'gatsby';

import SimpleMDE from 'react-simplemde-editor';
import marked from 'marked';

import Layout from '../components/layout';
import ItemDisplay from '../components/itemdisplay';
import ItemSources from '../components/itemsources';
import CrewFullEquipTree from '../components/crewfullequiptree';
import CommonCrewData from '../components/commoncrewdata';
import ExtraCrewDetails from '../components/extracrewdetails';

import CONFIG from '../components/CONFIG';

type StaticCrewPageProps = {
	data: {
		site: {
			siteMetadata: {
				titleTemplate: string;
				defaultTitle: string;
				defaultDescription: string;
				baseUrl: string;
			}
		};
		markdownRemark: {
			html: string;
			frontmatter: {
				name: string;
				memory_alpha: string;
				bigbook_tier?: number;
				events?: number;
				in_portal?: boolean;
				published: boolean;
			};
			rawMarkdownBody: string;
		};
		crewJson: any;
	};
	location: {
		pathname: string;
	}
};

type StaticCrewPageState = {
	selectedEquipment?: number;
	modalVisible: boolean;
	commentMarkdown: string;
	items: any[];
	comments: any[];
};

class StaticCrewPage extends Component<StaticCrewPageProps, StaticCrewPageState> {
	constructor(props) {
		super(props);

		this.state = {
			selectedEquipment: undefined,
			modalVisible: false,
			commentMarkdown: '', // TODO: load
			comments: [],
			items: []
		};
	}

	componentDidMount() {
		fetch('/structured/items.json')
			.then(response => response.json())
			.then(items => this.setState({ items }));


		// Disabled until we get big book folks on-board
		/*fetch(`${process.env.GATSBY_DATACORE_URL}api/comments?symbol=` + this.props.data.crewJson.edges[0].node.symbol)
			.then(response => response.json())
			.then(comments => {
				this.setState({ comments });

				const userName = this._getCurrentUsername();
				if (userName) {
					comments.forEach(comment => {
						if (comment.user.loginUserName === userName) {
							this.setState({ commentMarkdown: comment.markdown });
						}
					});
				}
			});*/
	}

	_getCurrentUsername() {
		const windowGlobal = typeof window !== 'undefined' && window;
		let isLoggedIn = windowGlobal && window.localStorage && window.localStorage.getItem('token') && window.localStorage.getItem('username');
		return isLoggedIn ? window.localStorage.getItem('username') : '';
	}

	render() {
		const { location } = this.props;
		const { markdownRemark, crewJson, site: { siteMetadata } } = this.props.data;
		if (crewJson.edges.length === 0) {
			return <span>Crew not found!</span>;
		}

		const { comments } = this.state;

		let hasBigBookEntry = markdownRemark && markdownRemark.frontmatter && markdownRemark.frontmatter.published;

		const userName = this._getCurrentUsername();

		const crew = crewJson.edges[0].node;
		return (
			<Layout narrowLayout={true}>
				<Helmet titleTemplate={siteMetadata.titleTemplate} defaultTitle={siteMetadata.defaultTitle}>
					<title>{crew.name}</title>
					<meta property='og:type' content='website' />
					<meta property='og:title' content={`${crew.name} - ${siteMetadata.defaultTitle}`} />
					<meta property='og:site_name' content='DataCore' />
					<meta property='og:image' content={`${process.env.GATSBY_ASSETS_URL}${crew.imageUrlPortrait}`} />
					<meta property='og:description' content={markdownRemark.rawMarkdownBody.trim() || siteMetadata.defaultDescription} />
					<meta property='og:url' content={`${siteMetadata.baseUrl}${location.pathname}`} />
				</Helmet>
				<CrewFullEquipTree
					visible={this.state.modalVisible}
					items={this.state.items}
					crew={crew}
					onClosed={() => this.setState({ modalVisible: false })}
				/>
				<Grid columns={2}>
					<Grid.Row stretched>
						<Grid.Column width={16}>
							<Header>
								{crew.name} <Rating defaultRating={crew.max_rarity} maxRating={crew.max_rarity} icon='star' size='large' disabled />
							</Header>
						</Grid.Column>
					</Grid.Row>
					<Grid.Row>
						<Grid.Column width={4}>
							{crew.series && <Image src={`/media/series/${crew.series}.png`} size='small' />}
							<Image src={`${process.env.GATSBY_ASSETS_URL}${crew.imageUrlFullBody}`} size='small' />
						</Grid.Column>
						<Grid.Column width={12}>
							<CommonCrewData crew={crew} markdownRemark={markdownRemark} />

							<div style={{ margin: '1em 0', textAlign: 'right' }}>
								<Button icon='add user' color='green' content='Preview in your roster' onClick={() => { this._addProspect(crew); }} />
							</div>

							{this.state.items.length > 0 ? (
								<React.Fragment>
									{this.renderEquipment(crew)}
									{this.renderEquipmentDetails(crew)}
									<Button
										onClick={() => this.setState({ modalVisible: true })}
										style={{ marginTop: '1em' }}
										content='Full equipment tree'
										icon='right arrow'
										labelPosition='right'
									/>
								</React.Fragment>
							) : (
									<div className='ui medium centered text active inline loader'>Loading items...</div>
								)}

							<Segment>
								<Header as='h4'>{crew.action.name}</Header>
								<p>
									Boosts {CONFIG.CREW_SHIP_BATTLE_BONUS_TYPE[crew.action.bonus_type]} by {crew.action.bonus_amount}
								</p>
								<p>
									Initialize: {crew.action.initial_cooldown}s, Cooldown: {crew.action.cooldown}s, Duration: {crew.action.duration}s
									</p>
								{crew.action.limit && <p>Uses Per Battle: {crew.action.limit}</p>}

								{crew.action.ability && (
									<p>
										Bonus ability:
										{CONFIG.CREW_SHIP_BATTLE_ABILITY_TYPE[crew.action.ability.type].replace('%VAL%', crew.action.ability.amount)}{' '}
										{crew.action.ability.condition > 0 && (
											<span>Trigger: {CONFIG.CREW_SHIP_BATTLE_TRIGGER[crew.action.ability.condition]}</span>
										)}
									</p>
								)}

								<p>
									<b>Accuracy:</b> +{crew.ship_battle.accuracy} <b>Crit Bonus:</b> +{crew.ship_battle.crit_bonus}{' '}
									{crew.ship_battle.crit_chance && (
										<span>
											<b>Crit Rating:</b> +{crew.ship_battle.crit_chance}{' '}
										</span>
									)}
									<b>Evasion:</b> +{crew.ship_battle.evasion}
								</p>
								{crew.action.penalty && (
									<p>
										Decrease {CONFIG.CREW_SHIP_BATTLE_BONUS_TYPE[crew.action.penalty.type]} by {crew.action.penalty.amount}
									</p>
								)}

								{this.renderChargePhases(crew.action, crew.action.charge_phases)}
							</Segment>
						</Grid.Column>
					</Grid.Row>
				</Grid>
				<Divider horizontal hidden />
				{hasBigBookEntry && (
					<React.Fragment>
						<div dangerouslySetInnerHTML={{ __html: markdownRemark.html }} />
						<div style={{ marginTop: '1em', textAlign: 'right' }}>
							-- <a href={`https://www.bigbook.app/crew/${crew.symbol}`}>The Big Book of Behold Advice</a>
						</div>
					</React.Fragment>
				)}
				{/*userName && (
						<div>
							<br />
							<p>Hello, {userName}. You can edit your comment below:</p>
							<SimpleMDE
								value={this.state.commentMarkdown}
								onChange={value => this._handleMarkDownChange(value)}
								options={{ hideIcons: ['fullscreen', 'guide', 'image', 'side-by-side'] }}
							/>
							<Button onClick={() => this._saveComment(crew.symbol, window.localStorage.getItem('token'))} content='Save comment' />
						</div>
					)}
					{comments && (
						<Comment.Group>
							<Header as='h3' dividing>
								Comments
							</Header>

							{comments.map(comment => (
								<Comment key={comment.id}>
									<Comment.Avatar src={comment.user.avatar || `${process.env.GATSBY_ASSETS_URL}crew_portraits_cm_empty_sm.png`} />
									<Comment.Content>
										<Comment.Author>{comment.user.loginUserName}</Comment.Author>
										<Comment.Metadata>
											<div>{comment.lastUpdate}</div>
										</Comment.Metadata>
										<Comment.Text>
											<div dangerouslySetInnerHTML={{ __html: marked(comment.markdown) }} />
										</Comment.Text>
									</Comment.Content>
								</Comment>
							))}
						</Comment.Group>
							)*/}
				<Divider horizontal hidden style={{ marginTop: '4em' }} />
				<ExtraCrewDetails
					crew_archetype_id={crew.archetype_id}
					max_rarity={crew.max_rarity}
					base_skills={crew.base_skills}
					traits={crew.traits} traits_hidden={crew.traits_hidden}
					unique_polestar_combos={crew.unique_polestar_combos}
				/>
			</Layout>
		);
	}

	_handleMarkDownChange(value) {
		this.setState({ commentMarkdown: value });
	}

	async _saveComment(symbol: string, token: string) {
		const { commentMarkdown } = this.state;

		fetch(`${process.env.GATSBY_DATACORE_URL}api/savecomment`, {
			method: 'post',
			headers: {
				'Content-Type': 'application/json'
			},
			body: JSON.stringify({ token, symbol, markdown: commentMarkdown })
		})
			.then(response => response.json())
			.then(res => {
				console.log(res);
			})
			.catch(err => {
				console.error(err);
			});
	}

	_addProspect(crew: any): void {
		const linkUrl = '/playertools?tool=crew';
		const linkState = {
			prospect: [crew.symbol]
		};
		navigate(linkUrl, { state: linkState });
	}

	renderEquipment(crew) {
		let options = [];
		crew.equipment_slots.forEach(es => {
			let equipment = this.state.items.find(item => item.symbol === es.symbol);
			if (!equipment) {
				console.warn(`Could not find item ${es.symbol}`);
				return;
			}

			options.push({
				key: es.symbol + '_' + es.level,
				text: `${equipment.name} (level ${es.level})`,
				value: es.symbol,
				content: (
					<Header
						icon={
							<ItemDisplay
								src={`${process.env.GATSBY_ASSETS_URL}${equipment.imageUrl}`}
								size={48}
								maxRarity={equipment.rarity}
								rarity={equipment.rarity}
							/>
						}
						content={equipment.name}
						subheader={`Level ${es.level}`}
					/>
				)
			});
		});

		return (
			<Dropdown
				selection
				fluid
				options={options}
				placeholder='Choose an equipment to see its details'
				onChange={(ev, { value }) => this.setState({ selectedEquipment: value as number })}
			/>
		);
	}

	renderEquipmentDetails(crew) {
		if (!this.state.selectedEquipment) {
			return <span />;
		}

		let es = crew.equipment_slots.find(es => es.symbol === this.state.selectedEquipment);
		let equipment = this.state.items.find(item => item.symbol === es.symbol);
		if (!equipment) {
			console.error('Could not find equipment for slot', es);
			return <span />;
		}

		if (!equipment.recipe) {
			return (
				<div>
					<br />
					<p>This item is not craftable, you can find it in these sources:</p>
					<ItemSources item_sources={equipment.item_sources} />
				</div>
			);
		}

		return (
			<div>
				<Grid columns={4} centered padded>
					{equipment.recipe.list.map(entry => {
						let recipeEntry = this.state.items.find(item => item.symbol === entry.symbol);
						return (
							<Grid.Column key={recipeEntry.name + recipeEntry.rarity} textAlign='center'>
								<Popup
									trigger={
										<Label as='a' style={{ background: CONFIG.RARITIES[recipeEntry.rarity].color }} image size='big'>
											<img src={`${process.env.GATSBY_ASSETS_URL}${recipeEntry.imageUrl}`} />x{entry.count}
										</Label>
									}
									header={CONFIG.RARITIES[recipeEntry.rarity].name + ' ' + recipeEntry.name}
									content={<ItemSources item_sources={recipeEntry.item_sources} />}
									wide
								/>
							</Grid.Column>
						);
					})}
				</Grid>
			</div>
		);
	}

	renderChargePhases(action, charge_phases) {
		if (!charge_phases) {
			return <span />;
		} else {
			let phases = [];
			let charge_time = 0;
			charge_phases.forEach((cp, idx) => {
				charge_time += cp.charge_time;
				let phaseDescription = `After ${charge_time}s, `;

				if (cp.ability_amount) {
					phaseDescription += CONFIG.CREW_SHIP_BATTLE_ABILITY_TYPE[action.ability.type].replace('%VAL%', cp.ability_amount);
				}

				if (cp.bonus_amount) {
					phaseDescription += `+${cp.bonus_amount} to ${CONFIG.CREW_SHIP_BATTLE_BONUS_TYPE[action.bonus_type]}`;
				}

				if (cp.duration) {
					phaseDescription += `, +${cp.duration}s duration`;
				}

				if (cp.cooldown) {
					phaseDescription += `, +${cp.cooldown}s cooldown`;
				}

				phases.push(<p key={idx}>{phaseDescription}</p>);
			});

			return (
				<div>
					<h4>Charge phases</h4>
					<div>{phases}</div>
				</div>
			);
		}
	}
}

export default StaticCrewPage;

export const query = graphql`
	query($slug: String!, $symbol: String!) {
		site {
			siteMetadata {
				defaultTitle: title
				titleTemplate
				defaultDescription: description
				baseUrl
			}
		}
		markdownRemark(fields: { slug: { eq: $slug } }) {
			rawMarkdownBody
			html
			frontmatter {
				name
				memory_alpha
				bigbook_tier
				events
				in_portal
				published
			}
		}
		crewJson: allCrewJson(filter: { symbol: { eq: $symbol } }) {
			edges {
				node {
					name
					short_name
					flavor
					series
					symbol
					archetype_id
					traits
					traits_named
					traits_hidden
					collections
					max_rarity
					imageUrlFullBody
					imageUrlPortrait
					date_added
					obtained
					...RanksFragment
					base_skills {
						security_skill {
							core
							range_min
							range_max
						}
						command_skill {
							core
							range_min
							range_max
						}
						diplomacy_skill {
							core
							range_min
							range_max
						}
						science_skill {
							core
							range_min
							range_max
						}
						medicine_skill {
							core
							range_min
							range_max
						}
						engineering_skill {
							core
							range_min
							range_max
						}
					}
					skill_data {
						rarity
						base_skills {
							security_skill {
								core
								range_min
								range_max
							}
							command_skill {
								core
								range_min
								range_max
							}
							diplomacy_skill {
								core
								range_min
								range_max
							}
							science_skill {
								core
								range_min
								range_max
							}
							medicine_skill {
								core
								range_min
								range_max
							}
							engineering_skill {
								core
								range_min
								range_max
							}
						}
					}
					cross_fuse_targets {
						symbol
						name
					}
					action {
						name
						bonus_type
						bonus_amount
						initial_cooldown
						cooldown
						duration
						limit
						penalty {
							type
							amount
						}
						ability {
							type
							amount
							condition
						}
						charge_phases {
							charge_time
							bonus_amount
							ability_amount
							cooldown
							duration
						}
					}
					equipment_slots {
						level
						symbol
					}
					ship_battle {
						accuracy
						crit_bonus
						crit_chance
						evasion
					}
					unique_polestar_combos
					nicknames {
						cleverThing
						creator
					}
				}
			}
		}
	}
`;