import { isExternalLogo, uploadLogo } from '@auto-launch/fetchers/get-logo';
import { getThemeVariation } from '@auto-launch/fetchers/get-variation';
import {
	getDesignBuildShape,
	getLogoShape,
	getPluginsShape,
	getStyleShape,
} from '@auto-launch/fetchers/shape';
import { importBuiltPagesImages } from '@auto-launch/functions/get-imported-images';
import {
	fetchWithTimeout,
	retryTwice,
	setStatus,
} from '@auto-launch/functions/helpers';
import { updateOption } from '@auto-launch/functions/wp';
import { useLaunchDataStore } from '@auto-launch/state/launch-data';
import { AI_HOST } from '@constants';
import { digest } from '@shared/api/digest';
import { __ } from '@wordpress/i18n';
import { mutate } from 'swr';

const fallback = null;
const headers = { 'Content-Type': 'application/json' };

// Left set, the launch screen waits forever on a design that never arrives.
const dropBuildId = () =>
	useLaunchDataStore.setState((s) => ({
		urlParams: { ...s.urlParams, 'build-id': '' },
	}));

export const handleDesignBuild = async ({ urlParams }) => {
	const buildId = urlParams?.['build-id'];
	if (!buildId) return fallback;

	// translators: this is for a action log UI. Keep it short
	setStatus(__('Loading your design', 'extendify-local'));

	const url = `${AI_HOST}/api/design/${encodeURIComponent(buildId)}`;
	const response = await retryTwice(() =>
		fetchWithTimeout(url, { headers }),
	).catch((error) => {
		return { ok: false, statusText: error.message, status: 0 };
	});

	if (!response?.ok) {
		digest({
			error: {
				message: response.statusText,
				name: 'FetchError',
				status: response.status,
			},
			details: { source: 'auto-launch', caller: 'handleDesignBuild' },
		});
		dropBuildId();
		return fallback;
	}

	try {
		const parsed = getDesignBuildShape.parse(await response.json());

		// Stash the site profile
		const profile = parsed.siteProfile;
		await updateOption('extendify_site_profile', JSON.stringify(profile));
		mutate('siteProfile', { siteProfile: profile }, false);

		// Stash the site style and variation
		const style = parsed.siteStyle;
		const fonts =
			style.fonts?.heading || style.fonts?.body ? style.fonts : null;
		const variation = await getThemeVariation(
			{ slug: style.colorPalette, fonts },
			{ fallback: true },
		);
		const siteStyle = { ...style, variation };
		await updateOption('extendify_site_style', siteStyle);
		await updateOption('extendify_animation_settings', {
			type: style.animation ?? 'fade',
			speed: 'medium',
		});
		mutate('siteStyle', getStyleShape.parse({ siteStyle }), false);

		// Stash the plugins
		const sitePlugins = parsed.selectedPlugins;
		mutate('sitePlugins', getPluginsShape.parse({ sitePlugins }), false);

		// The logo upload swaps logoUrl for a Media Library URL without the
		// logos-custom/ marker, so capture "is the brand's own logo" from the
		// source URL now.
		const hasExternalLogo = isExternalLogo(parsed.logoUrl);

		// Sideload the built-page images, and upload the logo alongside when the
		// build provided one. logoUrl is nullable; without it we skip the upload
		// so the siteLogo step falls through to AI logo generation.
		const uploads = [importBuiltPagesImages(parsed.builtPages)];
		if (parsed.logoUrl) {
			mutate(
				'siteLogo',
				getLogoShape.parse({ logoUrl: parsed.logoUrl }),
				false,
			);
			uploads.push(uploadLogo(parsed.logoUrl, { external: hasExternalLogo }));
		}
		const [builtPages] = await Promise.all(uploads);

		const designBuild = {
			buildId,
			...parsed,
			builtPages,
			hasExternalLogo,
			siteProfile: profile,
			siteStyle,
		};
		// Exclude `pages` from the spread: the pages step owns it (templates with
		// patterns); designBuild.pages (slug/name only) would clobber it.
		const { pages, ...topLevel } = designBuild;
		return { designBuild, ...topLevel };
	} catch (e) {
		digest({
			error: e,
			details: { source: 'auto-launch', caller: 'handleDesignBuild::parsing' },
		});
		console.error('handleDesignBuild:', e);
		dropBuildId();
		return fallback;
	}
};

// Prepend the design build's hero to the fetched home template. Full-page
// builds skip /api/home entirely and are assembled in handleHome.
export const applyDesignBuildHero = (patterns, designBuild) => {
	const builtHome = designBuild?.builtPages?.find((p) => p.slug === 'home');
	if (!builtHome?.patterns?.length) return patterns;
	return [...builtHome.patterns, ...patterns];
};

// Reorder pages to match the design build's page order; extras fall to the end.
export const applyDesignBuildOrder = (pages, designBuild) => {
	const order = designBuild?.pages?.map((p) => p.slug) ?? [];
	if (!order.length) return pages;
	return [
		...order.map((slug) => pages.find((t) => t.slug === slug)).filter(Boolean),
		...pages.filter((t) => !order.includes(t.slug)),
	];
};
