import SelectionFormatting, { MutableSelectionFormatting, defaultSelectionFormatting } from '../../SelectionFormatting';
import { syntaxTree } from '@codemirror/language';
import { EditorState } from '@codemirror/state';

const computeSelectionFormatting = (state: EditorState, globalSpellcheck: boolean): SelectionFormatting => {
	const range = state.selection.main;
	const formatting: MutableSelectionFormatting = {
		...defaultSelectionFormatting,
		selectedText: state.doc.sliceString(range.from, range.to),
		spellChecking: globalSpellcheck,
	};

	const parseLinkData = (nodeText: string) => {
		const linkMatch = nodeText.match(/\[([^\]]*)\]\(([^)]*)\)/);

		if (linkMatch) {
			return {
				linkText: linkMatch[1],
				linkURL: linkMatch[2],
			};
		}

		return {
			linkText: null,
			linkURL: null,
		};
	};

	// Find nodes that overlap/are within the selected region
	syntaxTree(state).iterate({
		from: range.from, to: range.to,
		enter: node => {
			// Checklists don't have a specific containing node. As such,
			// we're in a checklist if we've selected a 'Task' node.
			if (node.name === 'Task') {
				formatting.inChecklist = true;
			}

			// Only handle notes that contain the entire range.
			if (node.from > range.from || node.to < range.to) {
				return;
			}
			// Lazily compute the node's text
			const nodeText = () => state.doc.sliceString(node.from, node.to);

			switch (node.name) {
			case 'StrongEmphasis':
				formatting.bolded = true;
				break;
			case 'Emphasis':
				formatting.italicized = true;
				break;
			case 'ListItem':
				formatting.listLevel += 1;
				break;
			case 'BulletList':
				formatting.inUnorderedList = true;
				break;
			case 'OrderedList':
				formatting.inOrderedList = true;
				break;
			case 'TaskList':
				formatting.inChecklist = true;
				break;
			case 'InlineCode':
			case 'FencedCode':
				formatting.inCode = true;
				formatting.unspellCheckableRegion = true;
				break;
			case 'InlineMath':
			case 'BlockMath':
				formatting.inMath = true;
				formatting.unspellCheckableRegion = true;
				break;
			case 'ATXHeading1':
				formatting.headerLevel = 1;
				break;
			case 'ATXHeading2':
				formatting.headerLevel = 2;
				break;
			case 'ATXHeading3':
				formatting.headerLevel = 3;
				break;
			case 'ATXHeading4':
				formatting.headerLevel = 4;
				break;
			case 'ATXHeading5':
				formatting.headerLevel = 5;
				break;
			case 'URL':
				formatting.inLink = true;
				formatting.linkData = {
					...formatting.linkData,
					linkURL: nodeText(),
				};
				formatting.unspellCheckableRegion = true;
				break;
			case 'Link':
				formatting.inLink = true;
				formatting.linkData = parseLinkData(nodeText());
				break;
			}
		},
	});

	// The markdown parser marks checklists as unordered lists. Ensure
	// that they aren't marked as such.
	if (formatting.inChecklist) {
		if (!formatting.inUnorderedList) {
			// Even if the selection contains a Task, because an unordered list node
			// must contain a valid Task node, we're only in a checklist if we're also in
			// an unordered list.
			formatting.inChecklist = false;
		} else {
			formatting.inUnorderedList = false;
		}
	}

	if (formatting.unspellCheckableRegion) {
		formatting.spellChecking = false;
	}

	return formatting;
};
export default computeSelectionFormatting;

