import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { Controls } from '../controls';
import { useEntityBinding } from '../use-entity-binding';
import { useIsInvalidLink } from '../use-is-invalid-link';

globalThis.wpVitest.mockMatchMedia();

// Mock the updateAttributes function
let mockUpdateAttributes;
vi.mock( import( '../update-attributes' ), () => ( {
	updateAttributes: ( ...args ) => mockUpdateAttributes( ...args ),
} ) );

// Mock the useToolsPanelDropdownMenuProps hook
vi.mock( import( '../../../utils/hooks' ), () => ( {
	useToolsPanelDropdownMenuProps: () => ( {} ),
} ) );

// Mock the useEntityBinding hook
vi.mock( import( '../use-entity-binding' ), () => ( {
	useEntityBinding: vi.fn( () => ( {
		hasUrlBinding: false,
		isBoundEntityAvailable: false,
		clearBinding: vi.fn(),
	} ) ),
} ) );

// Mock the useIsInvalidLink hook
vi.mock( import( '../use-is-invalid-link' ), () => ( {
	useIsInvalidLink: vi.fn( () => [ false, false ] ),
} ) );

describe( 'Controls', () => {
	// Initialize the mock function
	beforeAll( () => {
		mockUpdateAttributes = vi.fn();
	} );

	const defaultProps = {
		attributes: {
			label: 'Test Link',
			url: 'https://example.com',
			description: 'Test description',
			rel: 'nofollow',
			opensInNewTab: false,
		},
		setAttributes: vi.fn(),
		setIsEditingControl: vi.fn(),
		clientId: 'test-client-id',
	};

	beforeEach( () => {
		vi.clearAllMocks();
		mockUpdateAttributes.mockClear();

		// Reset useEntityBinding mock to default
		useEntityBinding.mockReturnValue( {
			hasUrlBinding: false,
			isBoundEntityAvailable: false,
			clearBinding: vi.fn(),
		} );

		// Reset useIsInvalidLink mock to default
		useIsInvalidLink.mockReturnValue( [ false, false ] );
	} );

	it( 'renders all form controls', () => {
		render( <Controls { ...defaultProps } /> );

		expect( screen.getByLabelText( 'Text' ) ).toBeInTheDocument();
		expect( screen.getByText( 'Link to' ) ).toBeInTheDocument();
		expect(
			screen.getByLabelText( 'Open in new tab' )
		).toBeInTheDocument();
		expect( screen.getByLabelText( 'Description' ) ).toBeInTheDocument();
		expect( screen.getByLabelText( 'Rel attribute' ) ).toBeInTheDocument();
	} );

	it( 'strips HTML from label values', () => {
		const propsWithHtml = {
			...defaultProps,
			attributes: {
				...defaultProps.attributes,
				label: '<strong>Bold Text</strong>',
			},
		};
		render( <Controls { ...propsWithHtml } /> );

		const textInput = screen.getByLabelText( 'Text' );
		expect( textInput.value ).toBe( 'Bold Text' );
	} );

	it( 'handles all form field changes correctly', () => {
		render( <Controls { ...defaultProps } /> );

		// Test text change
		const textInput = screen.getByLabelText( 'Text' );
		fireEvent.change( textInput, { target: { value: 'New Label' } } );
		expect( defaultProps.setAttributes ).toHaveBeenCalledWith( {
			label: 'New Label',
		} );

		// Test description change
		const descriptionInput = screen.getByLabelText( 'Description' );
		fireEvent.change( descriptionInput, {
			target: { value: 'New Description' },
		} );
		expect( defaultProps.setAttributes ).toHaveBeenCalledWith( {
			description: 'New Description',
		} );

		// Test rel change
		const relInput = screen.getByLabelText( 'Rel attribute' );
		fireEvent.change( relInput, {
			target: { value: 'nofollow noopener' },
		} );
		expect( defaultProps.setAttributes ).toHaveBeenCalledWith( {
			rel: 'nofollow noopener',
		} );

		// Test checkbox change
		const checkbox = screen.getByLabelText( 'Open in new tab' );
		fireEvent.click( checkbox );
		expect( defaultProps.setAttributes ).toHaveBeenCalledWith( {
			opensInNewTab: true,
		} );
	} );

	describe( 'URL binding help text', () => {
		it( 'shows invalid link help text when bound entity is not available', () => {
			useEntityBinding.mockReturnValue( {
				hasUrlBinding: true,
				isBoundEntityAvailable: false,
				clearBinding: vi.fn(),
			} );

			const propsWithCategoryBinding = {
				...defaultProps,
				attributes: {
					...defaultProps.attributes,
					type: 'category',
					kind: 'taxonomy',
				},
			};

			render( <Controls { ...propsWithCategoryBinding } /> );

			expect(
				screen.getByText(
					'This link is invalid and will not appear on your site. Please update the link.'
				)
			).toBeInTheDocument();
		} );

		it( 'shows draft help text for draft entities', () => {
			useIsInvalidLink.mockReturnValue( [ false, true ] ); // isInvalid: false, isDraft: true

			const propsWithDraftPage = {
				...defaultProps,
				attributes: {
					...defaultProps.attributes,
					type: 'page',
					kind: 'post-type',
				},
			};

			render( <Controls { ...propsWithDraftPage } /> );

			expect(
				screen.getByText(
					'This link is to a draft page and will not appear on your site until the page is published.'
				)
			).toBeInTheDocument();
		} );

		it( 'shows draft help text for different entity types', () => {
			useIsInvalidLink.mockReturnValue( [ false, true ] );

			const propsWithDraftPost = {
				...defaultProps,
				attributes: {
					...defaultProps.attributes,
					type: 'post',
					kind: 'post-type',
				},
			};

			render( <Controls { ...propsWithDraftPost } /> );

			expect(
				screen.getByText(
					'This link is to a draft post and will not appear on your site until the post is published.'
				)
			).toBeInTheDocument();
		} );

		it( 'does not show help text for valid link', () => {
			const propsWithValidLink = {
				...defaultProps,
				attributes: {
					...defaultProps.attributes,
					url: 'https://example.com',
					type: 'page',
					kind: 'post-type',
				},
			};

			render( <Controls { ...propsWithValidLink } /> );

			// When link is valid (not invalid, not draft, no binding issues), no help text should be shown
			expect( screen.queryByText( /This link/ ) ).not.toBeInTheDocument();
		} );
	} );

	describe( 'View button', () => {
		it( 'shows "View link" for external URLs', () => {
			const propsWithExternalLink = {
				...defaultProps,
				attributes: {
					...defaultProps.attributes,
					url: 'https://example.com',
					// No kind or type for external links
				},
			};

			render( <Controls { ...propsWithExternalLink } /> );

			expect( screen.getByText( 'View' ) ).toBeVisible();
		} );

		it( 'shows "View page" for page links', () => {
			const propsWithPageLink = {
				...defaultProps,
				attributes: {
					...defaultProps.attributes,
					url: '/about',
					type: 'page',
					kind: 'post-type',
				},
			};

			render( <Controls { ...propsWithPageLink } /> );

			expect( screen.getByText( 'View' ) ).toBeVisible();
		} );

		it( 'shows "View post" for post links', () => {
			const propsWithPostLink = {
				...defaultProps,
				attributes: {
					...defaultProps.attributes,
					url: '/blog/my-post',
					type: 'post',
					kind: 'post-type',
				},
			};

			render( <Controls { ...propsWithPostLink } /> );

			expect( screen.getByText( 'View' ) ).toBeVisible();
		} );

		it( 'shows "View category" for category links', () => {
			const propsWithCategoryLink = {
				...defaultProps,
				attributes: {
					...defaultProps.attributes,
					url: '/category/tech',
					type: 'category',
					kind: 'taxonomy',
				},
			};

			render( <Controls { ...propsWithCategoryLink } /> );

			expect( screen.getByText( 'View' ) ).toBeVisible();
		} );

		it( 'shows "View link" for custom type links', () => {
			const propsWithCustomLink = {
				...defaultProps,
				attributes: {
					...defaultProps.attributes,
					url: 'https://example.com',
					type: 'custom',
					kind: 'custom',
				},
			};

			render( <Controls { ...propsWithCustomLink } /> );

			expect( screen.getByText( 'View' ) ).toBeVisible();
		} );
	} );
} );
