import { Box, ExtractShapeByProps, TLShapeId, resolveLineHeightPx } from '@tldraw/editor'
import classNames from 'classnames'
import React from 'react'
import { PlainTextArea } from '../text/PlainTextArea'
import { isLegacyAlign } from './legacyProps'
import { TextHelpers } from './TextHelpers'
import { useEditablePlainText } from './useEditablePlainText'

/** @public */
export interface PlainTextLabelProps {
	shapeId: TLShapeId
	type: ExtractShapeByProps<{ text: string }>['type']
	fontFamily: string
	fontSize: number
	lineHeight: number
	textAlign: 'start' | 'center' | 'end'
	verticalAlign: 'start' | 'middle' | 'end'
	wrap?: boolean
	text?: string
	labelColor: string
	bounds?: Box
	isSelected: boolean
	onKeyDown?(e: KeyboardEvent): void
	classNamePrefix?: string
	style?: React.CSSProperties
	textWidth?: number
	textHeight?: number
	padding?: number
	showTextOutline?: boolean
}

/**
 * Renders a text label that can be used inside of shapes.
 * The component has the ability to be edited in place and furthermore
 * supports rich text editing.
 *
 * @public @react
 */
export const PlainTextLabel = React.memo(function PlainTextLabel({
	shapeId,
	type,
	text: plaintext,
	labelColor,
	fontFamily,
	fontSize,
	lineHeight,
	textAlign,
	verticalAlign,
	wrap,
	isSelected,
	padding = 0,
	onKeyDown: handleKeyDownCustom,
	classNamePrefix,
	style,
	textWidth,
	textHeight,
	showTextOutline = true,
}: PlainTextLabelProps) {
	const { rInput, isEmpty, isEditing, isReadyForEditing, ...editableTextRest } =
		useEditablePlainText(shapeId, type, plaintext)

	const finalPlainText = TextHelpers.normalizeTextForDom(plaintext || '')
	const hasText = finalPlainText.length > 0

	const legacyAlign = isLegacyAlign(textAlign)

	if (!isEditing && !hasText) {
		return null
	}

	// TODO: probably combine tl-text and tl-arrow eventually
	// In case you're grepping for this, it breaks down as follows:
	// tl-text-label, tl-text-label__inner, tl-text-shape-label, tl-text
	// tl-arrow-label, tl-arrow-label__inner, tl-arrow
	const cssPrefix = classNamePrefix || 'tl-text'
	return (
		<div
			className={`${cssPrefix}-label tl-text-wrapper tl-plain-text-wrapper`}
			aria-hidden={!isEditing}
			data-hastext={!isEmpty}
			data-isediting={isEditing}
			data-is-ready-for-editing={isReadyForEditing}
			data-textwrap={!!wrap}
			data-isselected={isSelected}
			style={{
				fontFamily,
				textAlign,
				justifyContent:
					textAlign === 'center' || legacyAlign
						? 'center'
						: textAlign === 'end'
							? 'flex-end'
							: 'flex-start',
				alignItems:
					verticalAlign === 'middle'
						? 'center'
						: verticalAlign === 'end'
							? 'flex-end'
							: 'flex-start',
				padding,
				...style,
			}}
		>
			<div
				className={`${cssPrefix}-label__inner tl-text-content__wrapper`}
				style={{
					fontSize,
					lineHeight: `${resolveLineHeightPx(fontSize, lineHeight)}px`,
					minHeight: `${resolveLineHeightPx(fontSize, lineHeight)}px`,
					minWidth: Math.ceil(textWidth || 0),
					color: labelColor,
					width: textWidth ? Math.ceil(textWidth) : undefined,
					height: textHeight ? Math.ceil(textHeight) : undefined,
				}}
			>
				<div
					className={classNames(
						`${cssPrefix} tl-text tl-text-content`,
						showTextOutline ? 'tl-text__outline' : 'tl-text__no-outline'
					)}
					dir="auto"
				>
					{finalPlainText.split('\n').map((lineOfText, index) => (
						<div key={index} dir="auto">
							{lineOfText}
						</div>
					))}
				</div>
				{(isReadyForEditing || isSelected) && (
					<PlainTextArea
						// Fudge the ref type because we're using forwardRef and it's not typed correctly.
						ref={rInput as any}
						text={plaintext}
						isEditing={isEditing}
						shapeId={shapeId}
						{...editableTextRest}
						handleKeyDown={handleKeyDownCustom ?? editableTextRest.handleKeyDown}
					/>
				)}
			</div>
		</div>
	)
})
