// eslint-disable testing-library/no-dom-import
/**
 * External dependencies
 */
import { getByTestId, waitFor } from '@testing-library/dom';
import { getSettingWithCoercion } from '@woocommerce/settings';
import apiFetch from '@wordpress/api-fetch';

/**
 * Internal dependencies
 */
import {
	getMiniCartTotalsFromLocalStorage,
	getMiniCartTotalsFromServer,
	updateTotals,
	migrateAttributesToColorPanel,
} from '../data';

// This is a simplified version of the response of the Cart API endpoint.
const responseMock = {
	totals: {
		total_price: '1800',
		total_items: '1400',
		total_items_tax: '200',
		currency_code: 'USD',
		currency_symbol: '$',
		currency_minor_unit: 2,
		currency_decimal_separator: '.',
		currency_thousand_separator: ',',
		currency_prefix: '$',
		currency_suffix: '',
	},
	items_count: 2,
};
const localStorageMock = {
	totals: {
		total_price: '1800',
		total_items: '1400',
		total_items_tax: '200',
		currency_code: 'USD',
		currency_symbol: '$',
		currency_minor_unit: 2,
		currency_decimal_separator: '.',
		currency_thousand_separator: ',',
		currency_prefix: '$',
		currency_suffix: '',
	},
	itemsCount: 2,
};

const initializeLocalStorage = () => {
	Object.defineProperty( window, 'localStorage', {
		value: {
			getItem: jest
				.fn()
				.mockReturnValue( JSON.stringify( localStorageMock ) ),
			setItem: jest.fn(),
		},
		writable: true,
	} );
};

// This is a simplified version of the Mini-Cart DOM generated by MiniCart.php.
const getMiniCartDOM = () => {
	const div = document.createElement( 'div' );
	div.innerHTML = `
	<div class="wc-block-mini-cart">
		<div class="wc-block-mini-cart__amount" data-testid="amount"></div>
		<div class="wc-block-mini-cart__badge" data-testid="quantity"></div>
	</div>`;
	return div;
};

jest.mock( '@woocommerce/settings', () => {
	return {
		...jest.requireActual( '@woocommerce/settings' ),
		getSettingWithCoercion: jest.fn(),
	};
} );

jest.mock( '@wordpress/api-fetch' );

describe( 'Mini-Cart frontend script when "the display prices during cart and checkout" option is set to "Including Tax"', () => {
	beforeAll( () => {
		( getSettingWithCoercion as jest.Mock ).mockReturnValue( true );
	} );

	afterAll( () => {
		jest.resetModules();
	} );
	it( 'updates the cart contents based on the localStorage values', async () => {
		initializeLocalStorage();
		const container = getMiniCartDOM();
		document.body.appendChild( container );

		updateTotals( getMiniCartTotalsFromLocalStorage() );

		// Assert that we are rendering the amount.
		await waitFor( () =>
			expect( getByTestId( container, 'amount' ).textContent ).toBe(
				'$16.00'
			)
		);
		// Assert that we are rendering the quantity.
		await waitFor( () =>
			expect( getByTestId( container, 'quantity' ).textContent ).toBe(
				'2'
			)
		);
	} );

	it( 'updates the cart contents based on the API response', async () => {
		apiFetch.mockResolvedValue( responseMock );
		const container = getMiniCartDOM();
		document.body.appendChild( container );

		getMiniCartTotalsFromServer().then( updateTotals );

		// Assert we called the correct endpoint.
		await waitFor( () =>
			expect( apiFetch ).toHaveBeenCalledWith( {
				path: '/wc/store/v1/cart',
			} )
		);

		// Assert we saved the values returned to the localStorage.
		await waitFor( () =>
			expect( window.localStorage.setItem.mock.calls[ 0 ][ 1 ] ).toEqual(
				JSON.stringify( localStorageMock )
			)
		);

		// Assert that we are rendering the amount.
		await waitFor( () =>
			expect( getByTestId( container, 'amount' ).textContent ).toBe(
				'$16.00'
			)
		);
		// Assert that we are rendering the quantity.
		await waitFor( () =>
			expect( getByTestId( container, 'quantity' ).textContent ).toBe(
				'2'
			)
		);
		jest.restoreAllMocks();
	} );
} );

describe( 'Mini-Cart frontend script when "the display prices during cart and checkout" option is set to "Excluding Tax"', () => {
	beforeAll( () => {
		( getSettingWithCoercion as jest.Mock ).mockReturnValue( false );
	} );
	it( 'updates the cart contents based on the localStorage values', async () => {
		initializeLocalStorage();
		const container = getMiniCartDOM();
		document.body.appendChild( container );

		updateTotals( getMiniCartTotalsFromLocalStorage() );

		// Assert that we are rendering the amount.
		await waitFor( () =>
			expect( getByTestId( container, 'amount' ).textContent ).toBe(
				'$14.00'
			)
		);
		// Assert that we are rendering the quantity.
		await waitFor( () =>
			expect( getByTestId( container, 'quantity' ).textContent ).toBe(
				'2'
			)
		);
	} );

	it( 'updates the cart contents based on the API response', async () => {
		apiFetch.mockResolvedValue( responseMock );
		const container = getMiniCartDOM();
		document.body.appendChild( container );

		getMiniCartTotalsFromServer().then( updateTotals );

		// Assert we called the correct endpoint.
		await waitFor( () =>
			expect( apiFetch ).toHaveBeenCalledWith( {
				path: '/wc/store/v1/cart',
			} )
		);

		// Assert we saved the values returned to the localStorage.
		await waitFor( () =>
			expect( window.localStorage.setItem.mock.calls[ 0 ][ 1 ] ).toEqual(
				JSON.stringify( localStorageMock )
			)
		);

		// Assert that we are rendering the amount.
		await waitFor( () =>
			expect( getByTestId( container, 'amount' ).textContent ).toBe(
				'$14.00'
			)
		);
		// Assert that we are rendering the quantity.
		await waitFor( () =>
			expect( getByTestId( container, 'quantity' ).textContent ).toBe(
				'2'
			)
		);
		jest.restoreAllMocks();
	} );
} );

const mockAttributes = {
	miniCartIcon: 'cart',
	addToCartBehaviour: 'inline',
	hasHiddenPrice: false,
	cartAndCheckoutRenderStyle: true,
	priceColorValue: '#000000',
	iconColorValue: '#ffffff',
	productCountColorValue: '#ff0000',
};
describe( 'migrateAttributesToColorPanel tests', () => {
	test( 'it correctly migrates attributes to color panel', () => {
		const migratedAttributes =
			migrateAttributesToColorPanel( mockAttributes );
		expect( migratedAttributes ).toEqual( {
			miniCartIcon: 'cart',
			addToCartBehaviour: 'inline',
			hasHiddenPrice: false,
			cartAndCheckoutRenderStyle: true,
			priceColor: {
				color: '#000000',
			},
			iconColor: {
				color: '#ffffff',
			},
			productCountColor: {
				color: '#ff0000',
			},
		} );
	} );
} );
