import format from '@af/formatting/sync';
import { CURRENT_SURFACE_CSS_VAR } from '@atlaskit/tokens';
import { light as tokens } from '@atlaskit/tokens/tokens-raw';

import {
	capitalize,
	constructTokenFunctionCall,
	generateTypeDefs,
	type ShadowDefinition,
} from './utils';

type Token = {
	token: string;
	fallback: string | ShadowDefinition;
	isDeprecated: boolean;
};

// NB: Fallback CSS variables can be deleted when tokens are no longer behind a feature flag
const tokenStyles: {
	readonly opacity: {
		readonly objectName: 'opacity';
		readonly prefix: 'opacity.';
		readonly cssProperty: 'opacity';
		readonly filterFn: <T extends Token>(t: T) => boolean;
	};
	readonly shadow: {
		readonly objectName: 'shadow';
		readonly prefix: 'elevation.shadow.';
		readonly cssProperty: 'boxShadow';
		readonly filterFn: <T extends Token>(t: T) => boolean;
	};
	readonly surface: {
		readonly objectName: 'surfaceColor';
		readonly prefix: 'elevation.surface.';
		readonly cssProperty: '--ds-elevation-surface-current';
		readonly filterFn: <T extends Token>(t: T) => boolean;
	};
} = {
	opacity: {
		objectName: 'opacity',
		prefix: 'opacity.',
		cssProperty: 'opacity',
		filterFn: <T extends Token>(t: T): boolean => t.token.startsWith(tokenStyles.opacity.prefix),
	},
	shadow: {
		objectName: 'shadow',
		prefix: 'elevation.shadow.',
		cssProperty: 'boxShadow',
		filterFn: <T extends Token>(t: T): boolean => t.token.startsWith(tokenStyles.shadow.prefix),
	},
	surface: {
		objectName: 'surfaceColor',
		prefix: 'elevation.surface.',
		cssProperty: CURRENT_SURFACE_CSS_VAR,
		filterFn: <T extends Token>(t: T): boolean => t.token.startsWith(tokenStyles.surface.prefix),
	},
} as const;

const activeTokens = tokens
	.filter((t) => t.attributes.state !== 'deleted')
	.map(
		(t): Token => ({
			token: t.name,
			fallback: t.value as string | ShadowDefinition,
			isDeprecated: t.attributes.state === 'deprecated',
		}),
	);

export const createElevationStylesFromTemplate: (property: keyof typeof tokenStyles) => string = (
	property: keyof typeof tokenStyles,
) => {
	if (!tokenStyles[property]) {
		throw new Error(`[codegen] Unknown option found "${property}"`);
	}

	const { filterFn, objectName } = tokenStyles[property];

	const typeDefsTokens = activeTokens
		.filter(filterFn)
		// @ts-ignore
		.map((t) => t.token.replaceAll('.[default]', ''));

	return (
		format(
			`
export const ${objectName}Map: {
	${generateTypeDefs(typeDefsTokens)}
} = {
  ${activeTokens
		.filter(filterFn)
		// @ts-ignore
		.map((t) => ({ ...t, token: t.token.replaceAll('.[default]', '') }))
		.map((t) => {
			return `
        ${t.isDeprecated ? '// @deprecated' : ''}
        '${t.token}': ${constructTokenFunctionCall(t.token, t.fallback)}
      `.trim();
		})
		.join(',\n\t')}
} as const;`,
			'typescript',
		) + `\nexport type ${capitalize(objectName)} = keyof typeof ${objectName}Map;\n`
	);
};
