import { FC } from 'react';

import { RendererBgColor } from '../components/TokenRenderers/RendererBgColor';
import { RendererBorderColor } from '../components/TokenRenderers/RendererBorderColor';
import { RendererBorderImage } from '../components/TokenRenderers/RendererBorderImage';
import { RendererBorderRadius } from '../components/TokenRenderers/RendererBorderRadius';
import { RendererBorderWidth } from '../components/TokenRenderers/RendererBorderWidth';
import { RendererBoxShadow } from '../components/TokenRenderers/RendererBoxShadow';
import { RendererBrightness } from '../components/TokenRenderers/RendererBrightness';
import { RendererFgColor } from '../components/TokenRenderers/RendererFgColor';
import { RendererFontFamily } from '../components/TokenRenderers/RendererFontFamily';
import { RendererFontSize } from '../components/TokenRenderers/RendererFontSize';
import { RendererFontStyle } from '../components/TokenRenderers/RendererFontStyle';
import { RendererFontWeight } from '../components/TokenRenderers/RendererFontWeight';
import { RendererHeight } from '../components/TokenRenderers/RendererHeight';
import { RendererLetterSpacing } from '../components/TokenRenderers/RendererLetterSpacing';
import { RendererLineHeightPixels } from '../components/TokenRenderers/RendererLineHeightPixels';
import { RendererLineHeightRatio } from '../components/TokenRenderers/RendererLineHeightRatio';
import { RendererOutlineColor } from '../components/TokenRenderers/RendererOutlineColor';
import { RendererOutlineOffset } from '../components/TokenRenderers/RendererOutlineOffset';
import { RendererOutlineWidth } from '../components/TokenRenderers/RendererOutlineWidth';
import { RendererPaletteItem } from '../components/TokenRenderers/RendererPaletteItem';
import { RendererProps } from '../components/TokenRenderers/RendererProps';
import { RendererSize } from '../components/TokenRenderers/RendererSize';
import { RendererSpace } from '../components/TokenRenderers/RendererSpace';
import { RendererTextDecoration } from '../components/TokenRenderers/RendererTextDecoration';
import { RendererDuration } from '../components/TokenRenderers/RenderDuration';
import { RendererEasing } from '../components/TokenRenderers/RenderEasing';
import { ExtendedToken } from '../types';
import { RendererTransition } from '../components/TokenRenderers/RenderTransition';
import { RendererEasingCoordinate } from '../components/TokenRenderers/RendererEasingCoordinate';
import { RendererBackground } from '../components/TokenRenderers/RendererBackground';

type TokenRenderer = {
    renderer: FC<RendererProps>;
};

/**
 * pick a type for root tokens
 */
const typeFromPrefix: Record<string, string> = {
    'icon.size': 'size',
    spacing: 'space',
    sizing: 'space',
    radius: 'borderRadius',
    'dsInternalPrimitive.button.borderWeight': 'borderWidth',
    'icon.fieldLayout.width': 'horizontalPadding',
    'icon.fieldLayout.height': 'horizontalPadding',
    background: 'color',
    'color.border.ai.button.borderImage': 'borderImage',
    'color.border.ai.surface.borderImage': 'borderImage',
    'color.background.ai.surface.linearGradient': 'background',
    color: 'color',
    'spinner.icon.color': 'color',
    'dsInternalPrimitive.color': 'color',
    'exp.color': 'color',
    'badge.base.color': 'color',
    'badge.accent': 'color',
    content: 'color',
    elevation: 'boxShadow', // TODO: create a rendered similar to https://ethercreative.github.io/react-native-shadow-generator/
    dropShadow: 'boxShadow',
    'motion.components.interaction': 'transition',
    'calloutBanner.background': 'background',
    'alertBanner.background': 'background',
};

const suffixMap: Record<string, string> = {
    color: 'fgColor',
    lineHeight: 'lineHeightPixels',
    shadow: 'boxShadow',
    borderImage: 'borderImage',
    offset: 'size',
    x1: 'easingCoordinate',
    y1: 'easingCoordinate',
    x2: 'easingCoordinate',
    y2: 'easingCoordinate',
    short: 'duration',
    function: 'easing',
    functionName: 'easing',
};

const renderers: Record<string, TokenRenderer> = {
    background: {
        renderer: RendererBackground,
    },
    bgColor: {
        renderer: RendererBgColor,
    },
    borderColor: {
        renderer: RendererBorderColor,
    },
    borderImage: {
        renderer: RendererBorderImage,
    },
    borderRadius: {
        renderer: RendererBorderRadius,
    },
    brightness: {
        renderer: RendererBrightness,
    },
    color: {
        renderer: RendererPaletteItem,
    },
    fgColor: {
        renderer: RendererFgColor,
    },
    fontFamily: {
        renderer: RendererFontFamily,
    },
    fontSize: {
        renderer: RendererFontSize,
    },
    fontWeight: {
        renderer: RendererFontWeight,
    },
    fontStyle: {
        renderer: RendererFontStyle,
    },
    letterSpacing: {
        renderer: RendererLetterSpacing,
    },
    gap: {
        renderer: RendererSpace,
    },
    height: {
        renderer: RendererHeight,
    },
    horizontalPadding: {
        renderer: RendererSize,
    },
    lineHeightRatio: {
        renderer: RendererLineHeightRatio,
    },
    lineHeightPixels: {
        renderer: RendererLineHeightPixels,
    },
    outlineColor: {
        renderer: RendererOutlineColor,
    },
    outlineOffset: {
        renderer: RendererOutlineOffset,
    },
    outlineWidth: {
        renderer: RendererOutlineWidth,
    },
    borderWidth: {
        renderer: RendererBorderWidth,
    },
    padding: {
        renderer: RendererSize,
    },
    size: {
        renderer: RendererSize,
    },
    space: {
        renderer: RendererSpace,
    },
    boxShadow: {
        renderer: RendererBoxShadow,
    },
    typeface: {
        renderer: RendererFontFamily,
    },
    verticalPadding: {
        renderer: RendererSize,
    },
    textDecoration: {
        renderer: RendererTextDecoration,
    },
    duration: {
        renderer: RendererDuration,
    },
    easing: {
        renderer: RendererEasing,
    },
    transition: {
        renderer: RendererTransition,
    },
    easingCoordinate: {
        renderer: RendererEasingCoordinate,
    },
};

function getTypeFromPrefix(name: string): string | undefined {
    const match = Object.entries(typeFromPrefix).find(([prefix]) => name.startsWith(prefix));
    return match && match[1];
}

function getTypeFromSufix(name: string): string | undefined {
    const sufix = name.split('.').pop() || '';
    return sufix in suffixMap ? suffixMap[sufix] : sufix;
}

function getRenderer(token: ExtendedToken): TokenRenderer | undefined {
    const type = getTypeFromPrefix(token.name) || getTypeFromSufix(token.name) || '';

    return renderers[type];
}

export const tokenRenderer = (token: ExtendedToken): TokenRenderer => {
    const renderer = getRenderer(token);

    if (!renderer) {
        throw new Error(`No renderer for token "${token.name}".`);
    }

    return renderer;
};
