/**
 * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

import axios from '@nextcloud/axios'
import { mount } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
import { h } from 'vue'
import NcReferenceList from '../../../../src/components/NcRichText/NcReferenceList.vue'
import NcRichText from '../../../../src/components/NcRichText/NcRichText.vue'

vi.mock('@nextcloud/axios', () => ({
	default: {
		get: vi.fn().mockResolvedValue({ data: { ocs: { data: { references: {} } } } }),
	},
}))

describe('Foo', () => {
	it('renders a message and responds correctly to props changes', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Test {placeholder}',
			},
		})

		expect(wrapper.text()).toEqual('Test {placeholder}')
	})

	it('properly inserts a child component', async () => {
		const MyComponent = {
			name: 'MyComponent',
			render: () => {
				return h('div', 'MYCOMPONENT')
			},
		}
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Test {placeholder}',
				arguments: {
					placeholder: {
						component: MyComponent,
					},
				},
			},
		})

		expect(wrapper.text()).toEqual('Test MYCOMPONENT')
		expect(wrapper.findComponent(MyComponent).exists()).toBe(true)
	})

	it('properly inserts a child component with props', async () => {
		const MyComponent = {
			name: 'MyComponent',
			props: ['username'],
			render: () => {
				return h('div', 'MYCOMPONENT')
			},
		}
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Test {placeholder}',
				arguments: {
					placeholder: {
						component: MyComponent,
						props: {
							username: 'Jane',
						},
					},
				},
			},
		})

		expect(wrapper.text()).toEqual('Test MYCOMPONENT')
		expect(wrapper.findComponent(MyComponent).exists()).toBe(true)
		expect(wrapper.findComponent(MyComponent).vm.username).toBe('Jane')
	})
	it.each([
		['Fallback {placeholder}', {}, 'Fallback {placeholder}'],
		['{placeholder} fallback', {}, '{placeholder} fallback'],
		['Test {placeholder} {placeholder}', {}, 'Test {placeholder} {placeholder}'],
		['Test {placeholder}{placeholder}', {}, 'Test {placeholder}{placeholder}'],
		['Test {placeholder} between {placeholder}', {}, 'Test {placeholder} between {placeholder}'],
		['Test {placeholderA} {placeholderB}', {}, 'Test {placeholderA} {placeholderB}'],
		['Test {placeholderA}{placeholderB}', {}, 'Test {placeholderA}{placeholderB}'],
		['{placeholderA}', { placeholderA: 'A', placeholderB: 'B' }, 'A'],
		['{placeholderA} {placeholderB}', { placeholderA: 'A', placeholderB: 'B' }, 'A B'],
		['Test {placeholderA} {placeholderB}', { placeholderA: 'A', placeholderB: 'B' }, 'Test A B'],
		['Test {placeholderA} {placeholderA} {placeholderB}', { placeholderA: 'A', placeholderB: 'B' }, 'Test A A B'],
	])('text: %s', (text, attrs, result) => {
		const wrapper = mount(NcRichText, {
			props: {
				text,
				arguments: attrs,
			},
		})
		expect(wrapper.text()).toEqual(result)
	})

	it('properly inserts a link', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Testwith a link to https://example.com - go visit it',
				autolink: true,
			},
		})

		expect(wrapper.text()).toEqual('Testwith a link to https://example.com - go visit it')
		expect(wrapper.find('a').attributes('href')).toEqual('https://example.com')
	})

	it('properly inserts a newline', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Testwith a link to https://example.com \n go visit it',
				autolink: true,
			},
		})

		expect(wrapper.text()).toEqual('Testwith a link to https://example.com \n go visit it')
		expect(wrapper.find('a').attributes('href')).toEqual('https://example.com')
		expect(wrapper.html()).toContain('\n    go visit it')
	})

	it('properly inserts a link with brackets', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Test with a link to (https://example.com) - go visit it',
				autolink: true,
			},
		})
		expect(wrapper.text()).toEqual('Test with a link to (https://example.com) - go visit it')
		expect(wrapper.find('a').attributes('href')).toEqual('https://example.com')
	})

	it('properly inserts a link containing brackets', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Test with a link to (https://example.com/Link%20(Sub)) - go visit it',
				autolink: true,
			},
		})
		expect(wrapper.text()).toEqual('Test with a link to (https://example.com/Link%20(Sub)) - go visit it')
		expect(wrapper.find('a').attributes('href')).toEqual('https://example.com/Link%20(Sub)')
	})

	it('properly inserts a link containing brackets with markdown', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Test with a link to (https://example.com/Link%20(Sub)) - go visit it',
				autolink: true,
				useMarkdown: true,
			},
		})
		expect(wrapper.text()).toEqual('Test with a link to (https://example.com/Link%20(Sub)) - go visit it')
		expect(wrapper.find('a').attributes('href')).toEqual('https://example.com/Link%20(Sub)')
	})

	it('properly recognizes an url with a custom port and inserts a link', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Testwith a link to https://example.com:444 - go visit it',
				autolink: true,
			},
		})
		expect(wrapper.text()).toEqual('Testwith a link to https://example.com:444 - go visit it')
		expect(wrapper.find('a').attributes('href')).toEqual('https://example.com:444')
	})

	it('properly recognizes an url with an IP address and inserts a link', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Testwith a link to https://127.0.0.1/status.php - go visit it',
				autolink: true,
			},
		})
		expect(wrapper.text()).toEqual('Testwith a link to https://127.0.0.1/status.php - go visit it')
		expect(wrapper.find('a').attributes('href')).toEqual('https://127.0.0.1/status.php')
	})

	it('properly formats markdown', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: '**Testwith** a link *to* [Link](https://example:1337) - go visit it',
				autolink: false,
				useMarkdown: true,
			},
		})
		expect(wrapper.text()).toEqual('Testwith a link to Link - go visit it')
		expect(wrapper.find('a').attributes('href')).toEqual('https://example:1337')
		expect(wrapper.find('strong').text()).toEqual('Testwith')
		expect(wrapper.find('em').text()).toEqual('to')
	})

	it('does not autolink markdown link text that is already inside a link', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: '[https://example-nested.org](https://example.com)',
				autolink: true,
				useMarkdown: true,
			},
		})

		const links = wrapper.findAll('a')
		expect(links).toHaveLength(1)
		expect(links[0].attributes('href')).toEqual('https://example.com')
		expect(links[0].text()).toEqual('https://example-nested.org')
	})

	it('does not autolink deeply nested markdown link text that is already inside a link', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: '[**https://example-nested.org**](https://example.com)',
				autolink: true,
				useMarkdown: true,
			},
		})

		const links = wrapper.findAll('a')
		expect(links).toHaveLength(1)
		expect(links[0].attributes('href')).toEqual('https://example.com')
		expect(links[0].text()).toEqual('https://example-nested.org')
		expect(wrapper.find('strong').text()).toEqual('https://example-nested.org')
	})

	it('formats markdown is disabled', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: '**Testwith** a ~~link~~ *to* [Link](https://example:1337) - go visit it',
				autolink: true,
				useMarkdown: false,
			},
		})
		expect(wrapper.text()).toEqual('**Testwith** a ~~link~~ *to* [Link](https://example:1337) - go visit it')
	})

	it('formats interactive checkbox with extended markdown', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: '- [ ] task item',
				useExtendedMarkdown: true,
				interactive: true,
			},
		})
		expect(wrapper.text()).toEqual('task item')
		const checkbox = wrapper.findComponent({ name: 'NcCheckboxRadioSwitch' })
		expect(checkbox.exists()).toBeTruthy()
		await checkbox.vm.$emit('update:modelValue', true)
		expect(wrapper.emitted().interactTodo).toBeTruthy()
	})

	it('properly defines syntax in code blocks and highlights it', async () => {
		const wrapper = mount(NcRichText, {
			props: {
				text: '```js\nconsole.log(\'hello world\')\n```',
				autolink: false,
				useExtendedMarkdown: true,
			},
		})
		expect(wrapper.text()).toEqual('console.log(\'hello world\')')
		expect(wrapper.find('code').classes()).toEqual(['language-js'])
		await vi.dynamicImportSettled()
		expect(wrapper.find('code').classes()).toEqual(['hljs', 'language-js'])
	})

	it('strips URL links from text source if wrapped in inline/code blocks Markdown', () => {
		const testUrl = 'https://example.com/a_b'
		const wrapper = mount(NcRichText, {
			props: {
				text: 'Inline `https://example.com/inline_b`\n```\nStripped text https://example.com/fenced_b\n```\n\nPlain ' + testUrl,
				useMarkdown: true,
				referenceLimit: 1,
			},
		})

		expect(wrapper.findComponent(NcReferenceList).props('text').trim()).toMatch(/Inline\s.*Plain https:\/\/example.com\/a_b/)
		expect(axios.get).toHaveBeenCalledWith(expect.stringContaining(encodeURIComponent(testUrl)))
	})
})
