import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { getTranslations } from '../i18n';
import type { WidgetSizeConfig } from '../types';
import { SizeFlow } from './SizeFlow';

vi.mock('../imageUtils', () => ({
	fileToBase64: vi.fn().mockResolvedValue('data:image/jpeg;base64,WA=='),
	resizeAvatarImage: vi.fn().mockResolvedValue('data:image/jpeg;base64,WA=='),
}));

const PHOTO = 'data:image/jpeg;base64,WA==';
const VARIANTS = [{ variant_id: '12', size_label: 'M', available: true }];
const CONFIG: WidgetSizeConfig = {
	hasSizeGuide: true,
	guides: [{ id: 'g1', categories: { categories: ['shirts'] }, labels: ['M'] }],
	targeting: { mode: 'all' as const, categories: [], productIds: [] },
};

function renderFlow(api: any, sizeConfig = CONFIG) {
	return render(
		<SizeFlow
			t={getTranslations('en')}
			api={api}
			productId="7"
			productCategories={['shirts']}
			productVariants={VARIANTS}
			sizeConfig={sizeConfig}
			photo={PHOTO}
			onAddToCart={vi.fn().mockResolvedValue(true)}
			runId="run-1"
		/>
	);
}

describe('WooCommerce size flow', () => {
	beforeEach(() => localStorage.clear());

	it('shows the photo refusal before collecting height or weight', async () => {
		const api = {
			probePhotoQuality: vi.fn().mockResolvedValue({ ok: false, reason: 'not_full_body' }),
			estimate: vi.fn(),
		};
		renderFlow(api);
		await screen.findByText(/head to feet/i);
		expect(screen.queryByLabelText(/height/i)).toBeNull();
		expect(api.estimate).not.toHaveBeenCalled();
	});

	it('returns a variant-backed recommendation', async () => {
		const api = {
			probePhotoQuality: vi.fn().mockResolvedValue({ ok: true, reason: null }),
			estimate: vi.fn().mockResolvedValue({
				recommended_size: 'M',
				recommended_variant_id: '12',
				confidence: 0.8,
				confidence_band: 'good',
				explanation: '',
				alternatives: [],
			}),
		};
		renderFlow(api);
		await waitFor(() => expect(api.probePhotoQuality).toHaveBeenCalled());
		fireEvent.click(screen.getByRole('button', { name: /find my size/i }));
		fireEvent.change(screen.getByLabelText(/height/i), { target: { value: '175' } });
		fireEvent.click(screen.getByRole('button', { name: /get my size/i }));
		await screen.findByText('M');
		expect(api.estimate).toHaveBeenCalledWith(
			expect.objectContaining({ productId: '7', heightCm: 175, productVariants: VARIANTS }),
			expect.any(AbortSignal)
		);
	});

	it('sends the shopper fit preference only when the merchant enabled the choice', async () => {
		const api = {
			probePhotoQuality: vi.fn().mockResolvedValue({ ok: true, reason: null }),
			estimate: vi.fn().mockResolvedValue({
				recommended_size: 'M', recommended_variant_id: '12', confidence: 0.8,
				confidence_band: 'good', explanation: '', alternatives: [],
			}),
		};
		renderFlow(api, { ...CONFIG, fitPreferenceEnabled: true, defaultFitPreference: 'regular' as const });
		await waitFor(() => expect(api.probePhotoQuality).toHaveBeenCalled());
		fireEvent.click(screen.getByRole('button', { name: /find my size/i }));
		fireEvent.change(screen.getByLabelText(/height/i), { target: { value: '175' } });
		fireEvent.change(screen.getByLabelText(/prefer it to fit/i), { target: { value: 'loose' } });
		fireEvent.click(screen.getByRole('button', { name: /get my size/i }));
		await waitFor(() => expect(api.estimate).toHaveBeenCalledWith(
			expect.objectContaining({ fitPreference: 'loose' }),
			expect.any(AbortSignal)
		));
	});

	it('can re-estimate with a replacement measurement photo', async () => {
		const answer = {
			recommended_size: 'M', recommended_variant_id: '12', confidence: 0.5,
			confidence_band: 'low', explanation: '', alternatives: [], improvement_options: ['retake_photo'],
		};
		const api = {
			probePhotoQuality: vi.fn().mockResolvedValue({ ok: true, reason: null }),
			estimate: vi.fn().mockResolvedValue(answer),
		};
		renderFlow(api);
		await waitFor(() => expect(api.probePhotoQuality).toHaveBeenCalled());
		fireEvent.click(screen.getByRole('button', { name: /find my size/i }));
		fireEvent.change(screen.getByLabelText(/height/i), { target: { value: '175' } });
		fireEvent.click(screen.getByRole('button', { name: /get my size/i }));
		const input = await screen.findByLabelText(/better full-body photo/i);
		fireEvent.change(input, { target: { files: [new File(['photo'], 'body.jpg', { type: 'image/jpeg' })] } });
		await waitFor(() => expect(api.estimate).toHaveBeenCalledTimes(2));
	});
});
