/*
	GoToSocial
	Copyright (C) GoToSocial Authors admin@gotosocial.org
	SPDX-License-Identifier: AGPL-3.0-or-later

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

import React, { useCallback, useEffect } from "react";

import { useTextInput, useComboBoxInput, useCheckListInput } from "../../../../lib/form";

import useFormSubmit from "../../../../lib/form/submit";

import CheckList from "../../../../components/check-list";
import { CategorySelect } from '../category-select';

import { TextInput } from "../../../../components/form/inputs";
import MutationButton from "../../../../components/form/mutation-button";
import { Error } from "../../../../components/error";
import { useSearchItemForEmojiMutation, usePatchRemoteEmojisMutation } from "../../../../lib/query/admin/custom-emoji";

export default function StealThisLook({ emojiCodes }) {
	const [searchStatus, result] = useSearchItemForEmojiMutation();
	const urlField = useTextInput("url");

	function submitSearch(e) {
		e.preventDefault();
		if (urlField.value !== undefined && urlField.value.trim().length != 0) {
			searchStatus(urlField.value);
		}
	}

	return (
		<div className="parse-emoji">
			<h2>Steal this look</h2>
			<form onSubmit={submitSearch}>
				<div className="form-field text">
					<label htmlFor="url">
						Link to a status:
					</label>
					<div className="row">
						<input
							id="url"
							name="url"
							type="url"
							pattern="(http|https):\/\/.+"
							onChange={urlField.onChange}
							value={urlField.value}
						/>
						<button disabled={result.isLoading}>
							<i className={[
								"fa fa-fw",
								(result.isLoading
									? "fa-refresh fa-spin"
									: "fa-search"),
							].join(" ")} aria-hidden="true" title="Search" />
							<span className="sr-only">Search</span>
						</button>
					</div>
				</div>
			</form>
			<SearchResult result={result} localEmojiCodes={emojiCodes} />
		</div>
	);
}

function SearchResult({ result, localEmojiCodes }) {
	const { error, data, isSuccess, isError } = result;

	if (!(isSuccess || isError)) {
		return null;
	}

	if (error == "NONE_FOUND") {
		return "No results found";
	} else if (error == "LOCAL_INSTANCE") {
		return <b>This is a local user/status, all referenced emoji are already on your instance</b>;
	} else if (error != undefined) {
		return <Error error={result.error} />;
	}

	if (data.list.length == 0) {
		return <b>This {data.type == "statuses" ? "status" : "account"} doesn't use any custom emoji</b>;
	}

	return (
		<CopyEmojiForm
			localEmojiCodes={localEmojiCodes}
			type={data.type}
			emojiList={data.list}
		/>
	);
}

function CopyEmojiForm({ localEmojiCodes, type, emojiList }) {
	const form = {
		selectedEmoji: useCheckListInput("selectedEmoji", {
			entries: emojiList,
			uniqueKey: "id",
		}),
		category: useComboBoxInput("category"),
	};

	const [formSubmit, result] = useFormSubmit(
		form,
		usePatchRemoteEmojisMutation(),
		{
			changedOnly: false,
			onFinish: ({ data }) => {
				if (data) {
					// uncheck all successfully processed emoji
					const processed = data.map((emoji) => {
						return [emoji.id, { checked: false }];
					});
					form.selectedEmoji.updateMultiple(processed);
				}
			},
		},
	);

	const buttonsInactive = form.selectedEmoji.someSelected
		? {
			disabled: false,
			title: "",
		}
		: {
			disabled: true,
			title: "No emoji selected, cannot perform any actions",
		};

	const checkListExtraProps = useCallback(() => ({ localEmojiCodes }), [localEmojiCodes]);

	return (
		<div className="parsed">
			<span>This {type == "statuses" ? "status" : "account"} uses the following custom emoji, select the ones you want to copy/disable:</span>
			<form onSubmit={formSubmit}>
				<CheckList
					field={form.selectedEmoji}
					header={<></>}
					EntryComponent={EmojiEntry}
					getExtraProps={checkListExtraProps}
				/>

				<CategorySelect
					field={form.category}
					children={[]}
				/>

				<div className="action-buttons row">
					<MutationButton
						name="copy"
						label="Copy to local emoji"
						result={result}
						showError={false}
						{...buttonsInactive}
					/>
					<MutationButton
						name="disable"
						label="Disable"
						result={result}
						className="button danger"
						showError={false}
						{...buttonsInactive}
					/>
				</div>
				{result.error && (
					Array.isArray(result.error)
						? <ErrorList errors={result.error} />
						: <Error error={result.error} />
				)}
			</form>
		</div>
	);
}

function ErrorList({ errors }) {
	return (
		<div className="error">
			One or multiple emoji failed to process:
			{errors.map(([shortcode, err]) => (
				<div key={shortcode}>
					<b>{shortcode}:</b> {err}
				</div>
			))}
		</div>
	);
}

function EmojiEntry({ entry: emoji, onChange, extraProps: { localEmojiCodes } }) {
	const shortcodeField = useTextInput("shortcode", {
		defaultValue: emoji.shortcode,
		validator: function validateShortcode(code) {
			return (emoji.checked && localEmojiCodes.has(code))
				? "Shortcode already in use"
				: "";
		},
	});

	useEffect(() => {
		if (emoji.valid != shortcodeField.valid) {
			onChange({ valid: shortcodeField.valid });
		}
	}, [onChange, emoji.valid, shortcodeField.valid]);

	useEffect(() => {
		shortcodeField.validate();
		// only need this update if it's the emoji.checked that updated, not shortcodeField
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [emoji.checked]);

	return (
		<>
			<img className="emoji" src={emoji.url} title={emoji.shortcode} />

			<TextInput
				field={shortcodeField}
				onChange={(e) => {
					shortcodeField.onChange(e);
					onChange({ shortcode: e.target.value, checked: true });
				}}
			/>
		</>
	);
}
