import type { Extension } from '@codemirror/state';
import { EditorView as CodeMirror } from '@codemirror/view';

import type { EditorContentMode } from '@atlaskit/editor-common/types';
import { fg } from '@atlaskit/platform-feature-flags';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { token } from '@atlaskit/tokens';

const shouldUseCompactTypography = (contentMode?: EditorContentMode) =>
	contentMode === 'compact' ||
	(expValEquals('cc_editor_ai_content_mode', 'variant', 'test') &&
		fg('platform_editor_content_mode_button_mvp'));

const getLineHeight = (contentMode?: EditorContentMode) =>
	shouldUseCompactTypography(contentMode) ? '1.5em' : '1.5rem';

const getFontSize = (contentMode?: EditorContentMode) =>
	shouldUseCompactTypography(contentMode) ? '0.875em' : '0.875rem';

type ThemeOptions = {
	contentMode?: EditorContentMode;
};

export const cmTheme = (options?: ThemeOptions): Extension =>
	CodeMirror.theme({
		'&': {
			backgroundColor: token('color.background.neutral'),
			padding: '0',
			marginTop: token('space.100'),
			marginBottom: token('space.100'),
			// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
			fontSize: getFontSize(options?.contentMode),
			// Custom syntax styling to match existing styling
			// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
			lineHeight: getLineHeight(options?.contentMode),
		},
		'&.cm-focused': {
			outline: 'none',
		},
		'.cm-line': {
			padding: '0',
		},
		'&.cm-editor.code-block.danger': {
			backgroundColor: token('color.background.danger'),
		},
		'.cm-content[aria-readonly="true"]': {
			caretColor: 'transparent',
		},
		'.cm-content': {
			cursor: 'text',
			caretColor: token('color.text'),
			margin: token('space.100'),
			padding: token('space.0'),
		},
		'.cm-scroller': {
			backgroundColor: token('color.background.neutral'),
			// Custom syntax styling to match existing styling
			// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
			lineHeight: 'unset',
			fontFamily: token('font.family.code'),
			borderRadius: token('radius.small'),
			backgroundImage: overflowShadow({
				leftCoverWidth: token('space.300'),
			}),
			backgroundAttachment: 'local, local, local, local, scroll, scroll, scroll, scroll',
		},
		'&.cm-focused .cm-cursor': {
			borderLeftColor: token('color.text'),
		},
		'.cm-gutter': {
			padding: token('space.100'),
		},
		'.cm-gutters': {
			backgroundColor: token('color.background.neutral'),
			border: 'none',
			padding: token('space.0'),
			color: token('color.text.subtlest'),
			...(expValEquals('platform_editor_code_block_q4_lovability', 'isEnabled', true) && {
				// CodeMirror defaults this to height: 100%, which can resolve against an indefinite
				// parent height in content-height editor and prevent flex stretching when gutter
				// content is sparse, such as fold-only gutters.
				height: 'unset',
				alignSelf: 'stretch',
			}),
		},
		'.cm-lineNumbers .cm-gutterElement': {
			paddingLeft: token('space.0'),
			paddingRight: token('space.0'),
			minWidth: 'unset',
		},
		// Set the gutter element min height to prevent flicker of styling while
		// codemirror is calculating (which happens after an animation frame).
		// Example problem: https://github.com/codemirror/dev/issues/1076
		// Ignore the first gutter element as it is a special hidden element.
		'.cm-gutterElement:not(:first-child)': {
			// eslint-disable-next-line @atlaskit/design-system/use-tokens-typography
			minHeight: getLineHeight(options?.contentMode),
		},
	});

export const codeFoldingTheme: Extension = CodeMirror.theme({
	'.cm-gutter': {
		paddingLeft: token('space.075'),
		paddingTop: token('space.100'),
		paddingBottom: token('space.100'),
		paddingRight: token('space.0'),
	},
	'.cm-foldGutter': {
		paddingLeft: token('space.050'),
	},
	'.cm-gutterElement:has([data-marker-dom-element="true"])': {
		color: token('color.icon.subtle'),
	},
	'.cm-gutterElement:has([data-marker-dom-element="true"]):hover': {
		color: token('color.text.accent.gray.bolder'),
	},
	'.cm-foldPlaceholder': {
		// To give spacing between lines
		height: '20px',
		backgroundColor: token('color.background.accent.gray.subtlest'),
		border: 'none',
		color: token('color.text'),
		outline: `1px solid ${token('color.border.accent.gray')}`,
		paddingLeft: token('space.025'),
		paddingRight: token('space.025'),
	},
	'.cm-foldPlaceholder:hover': {
		backgroundColor: token('color.background.accent.gray.subtlest.hovered'),
	},
});

/**
 * Copied directly from `packages/editor/editor-shared-styles/src/overflow-shadow/overflow-shadow.ts`
 * `CodeMirror` does not support emotion styling so this has been re-created.
 */
function overflowShadow({
	leftCoverWidth,
	rightCoverWidth,
}: {
	leftCoverWidth?: string;
	rightCoverWidth?: string;
}) {
	const width = token('space.100');
	const leftCoverWidthResolved = leftCoverWidth || width;
	const rightCoverWidthResolved = rightCoverWidth || width;

	return `
  linear-gradient(
    to right,
    ${token('color.background.neutral')} ${leftCoverWidthResolved},
    transparent ${leftCoverWidthResolved}
  ),
  linear-gradient(
    to right,
    ${token('elevation.surface.raised')} ${leftCoverWidthResolved},
    transparent ${leftCoverWidthResolved}
  ),
  linear-gradient(
    to left,
    ${token('color.background.neutral')} ${rightCoverWidthResolved},
    transparent ${rightCoverWidthResolved}
  ),
  linear-gradient(
    to left,
    ${token('elevation.surface.raised')} ${rightCoverWidthResolved},
    transparent ${rightCoverWidthResolved}
  ),
  linear-gradient(
    to left,
    ${token('elevation.shadow.overflow.spread')} 0,
    ${token('utility.UNSAFE.transparent')}  ${width}
  ),
  linear-gradient(
    to left,
    ${token('elevation.shadow.overflow.perimeter')} 0,
    ${token('utility.UNSAFE.transparent')}  ${width}
  ),
  linear-gradient(
    to right,
    ${token('elevation.shadow.overflow.spread')} 0,
    ${token('utility.UNSAFE.transparent')}  ${width}
  ),
  linear-gradient(
    to right,
    ${token('elevation.shadow.overflow.perimeter')} 0,
    ${token('utility.UNSAFE.transparent')}  ${width}
  )
`;
}
