import * as React from 'react'
import {__, _x, sprintf} from '@wordpress/i18n'

import {
	useState,
	useMemo,
	useRef,
	useEffect,
} from '@wordpress/element'

import {
	__experimentalVStack as VStack,
	__experimentalView as View,
	TextareaControl,
	ToggleControl,
	BaseControl,
} from '@wordpress/components'

import {
	Button,
	ButtonGroup,
	UserJsonView,
} from '@ska/components'

import {
	useSkaBlocksOptions,
} from '@ska/shared'

import {
	getRandomSuggestions,
	getSuggestions,
} from '../../suggestions'

import {
	ModelPicker,
} from '../model-picker'

import type {
	Message,
	AISession,
} from '../../types'

import './style.scss'

export interface ChatProps {
	/** AI session context. */
	session: AISession
	/** Current prompt. */
	prompt: string
	/** Update prompt. */
	setPrompt: (nextPrompt: string) => void
	/** Whether user needs to enter a prompt. */
	promptRequired?: boolean
	/** Custom model. */
	model: string
	/** Update custom model. */
	setModel: (nextModel: string) => void
	/** Content to display above the chat. */
	description?: React.ReactNode
	/** Additional suggestion options. */
	suggestions?: string[]
	/** Loading AI response. */
	isLoading?: boolean
	/** Current state. */
	messages: Message[]
	/** Prompt that was sent to AI. */
	onSend: (prompt: string) => void
	/** Abort query. */
	onAbort: () => void
	/** End chat session. */
	onEndSession?: () => void
}

const noop = (...args: any) => {}
const NO_SUGGESTIONS: string[] = []

const Chat: React.FC<ChatProps> = ({
	session,
	prompt,
	setPrompt,
	promptRequired = true,
	model,
	setModel,
	description = null,
	suggestions: additionalSuggestions = NO_SUGGESTIONS,
	isLoading,
	messages,
	onSend,
	onAbort,
	onEndSession = noop,
}) => {

	const {
		openRouterModel,
	} = useSkaBlocksOptions()

	const {
		mode = 'html',
		value,
	} = session

	const hasValue = !!value

	const promptRef = useRef<HTMLTextAreaElement | null>(null)
	const [includeValue, setIncludeValue] = useState(true)
	const [overrideModel, setOverrideModel] = useState(!!model)

	const getPrompt = (prompt: string = '') => {

		let msg = prompt || (promptRequired ? '{Prompt or suggestion}' : 'Please do as instructed by the system prompt.')

		if(hasValue) {

			switch(mode) {

				case 'html':
					if(includeValue) {
						msg += `\n\nThis is the current HTML, please make the modifications to this:\n${value}`
					}
				break

				case 'text':
					msg += `\n\nThis is the current text, please make the modifications to this:\n${value}`
				break
			}
		} else {

			switch(mode) {

				case 'text':
					msg += `\n\nThere is currently no text, please generate something related to the request above.`
				break
			}
		}

		return msg
	}

	const sendPrompt = (prompt: string) => {
		onSend(getPrompt(prompt))
	}

	const {
		suggestions = NO_SUGGESTIONS,
		placeholder = '',
	} = useMemo(() => {

		const suggestionsFor = (hasValue ? `edit-${mode}` : `initial-${mode}`) as 'edit-text'

		return {
			suggestions: NO_SUGGESTIONS,
			...(mode === 'html' && {
				placeholder: getRandomSuggestions(suggestionsFor, 1)[0],
				suggestions: [...getRandomSuggestions(suggestionsFor, 10), ...additionalSuggestions],
			}),
			...(mode === 'text' && {
				placeholder: getRandomSuggestions(suggestionsFor, 1)[0],
				suggestions: [...getSuggestions(suggestionsFor), ...additionalSuggestions],
			}),
			...(mode === 'seo' && {
				placeholder: hasValue ? _x('Improvement suggestions', 'SEO prompt placeholder', 'ska-blocks') : _x('Optional additional details', 'SEO prompt placeholder', 'ska-blocks'),
			}),
		}
	}, [hasValue, mode, additionalSuggestions])

	useEffect(() => {
		promptRef?.current?.focus()
	}, [])

	return (
		<View className='ska-ai-chat'>
			<VStack>
				{isLoading && <>
					<p className='description'>{__('Awaiting response from AI…', 'ska-blocks')}</p>
					<div className='ska-ai-chat__footer'>
						<Button
							variant='secondary'
							isDestructive
							children={__('Abort', 'ska-blocks')}
							onClick={() => {
								onAbort()
							}}
						/>
						<div>
							<Button
								variant='link'
								isDestructive
								children={__('End session', 'ska-blocks')}
								onClick={onEndSession}
							/>
							<UserJsonView
								value={() => ({
									messages,
									nextPrompt: getPrompt(prompt),
								})}
							/>
						</div>
					</div>
				</>}
				{!isLoading && <>
					{description}
					{suggestions.length > 0 && <>
						<ButtonGroup.Radio
							label={__('Click on a suggestion…', 'ska-blocks')}
							isSmall
							pills
							options={suggestions.map(v => ({label: v, value: v}))}
							onChange={suggestion => {
								suggestion && sendPrompt(suggestion)
							}}
						/>
					</>}
					<TextareaControl
						ref={promptRef}
						label={suggestions.length > 0 ? __('…or write a prompt', 'ska-blocks') : __('Write a prompt', 'ska-blocks')}
						placeholder={placeholder ? `${placeholder}…` : ''}
						value={prompt}
						onChange={setPrompt}
						__nextHasNoMarginBottom
					/>
					{hasValue && mode === 'html' && <>
						<ToggleControl
							label={__('Include current HTML in the prompt', 'ska-blocks')}
							checked={includeValue}
							onChange={setIncludeValue}
							__nextHasNoMarginBottom
						/>
					</>}
					<ToggleControl
						label={__('Use a different model', 'ska-blocks')}
						help={model || openRouterModel}
						checked={overrideModel}
						onChange={() => {
							const nextOverrideModel = !overrideModel
							if(!nextOverrideModel && model) {
								setModel('')
							}
							setOverrideModel(nextOverrideModel)
						}}
						__nextHasNoMarginBottom
					/>
					{overrideModel && (
						<BaseControl
							label={__('Select a model', 'ska-blocks')}
							help={sprintf(__('Default model: %s', 'ska-blocks'), openRouterModel)}
							__nextHasNoMarginBottom
						>
							<ModelPicker
								showFilters={true}
								value={model}
								onChange={setModel}
							/>
						</BaseControl>
					)}
					<div className='ska-ai-chat__footer'>
						<Button
							variant='primary'
							children={__('Generate', 'ska-blocks')}
							isBusy={isLoading}
							disabled={promptRequired && !prompt}
							onClick={() => {
								sendPrompt(prompt)
							}}
						/>
						<div>
							<Button
								variant='link'
								isDestructive
								children={`${__('End session', 'ska-blocks')}${messages.length > 1 ? ` (${messages.length})` : ''}`}
								onClick={onEndSession}
							/>
							<UserJsonView
								value={() => ({
									models: model || openRouterModel,
									messages,
									nextPrompt: getPrompt(prompt),
								})}
							/>
						</div>
					</div>
				</>}
			</VStack>
		</View>
	)
}

export default Chat
