import {
    DEFAULT_ELEMENT_SETTINGS,
    DEFAULT_GLOBAL_VALUES,
    DEFAULT_WIDGET_SETTINGS,
    type ElementSettings,
    type PresetGlobalValues,
    type WidgetSettings,
} from '../types/appearance'

/**
 * Merge sparse saved element settings with full defaults.
 * Per-section deep merge ensures ALL properties have values.
 *
 * This is the SINGLE source of truth for admin preview data assembly.
 * Used by: listing card (PresetCard), GeneralChatViewSection, bot tab.
 *
 * Matches the pattern previously inline in GeneralChatViewSection:
 *   header: { ...DEFAULT.header, ...saved.header }
 */
export function mergeElementSettings(
    saved: Partial<ElementSettings> | null | undefined
): ElementSettings {
    if (!saved) return { ...DEFAULT_ELEMENT_SETTINGS }

    return {
        header: { ...DEFAULT_ELEMENT_SETTINGS.header, ...saved.header },
        chatWindow: { ...DEFAULT_ELEMENT_SETTINGS.chatWindow, ...saved.chatWindow },
        chatBubble: { ...DEFAULT_ELEMENT_SETTINGS.chatBubble, ...saved.chatBubble },
        userMessage: { ...DEFAULT_ELEMENT_SETTINGS.userMessage, ...saved.userMessage },
        botMessage: { ...DEFAULT_ELEMENT_SETTINGS.botMessage, ...saved.botMessage },
        inputArea: { ...DEFAULT_ELEMENT_SETTINGS.inputArea, ...saved.inputArea },
        typingIndicator: { ...DEFAULT_ELEMENT_SETTINGS.typingIndicator, ...(saved.typingIndicator || {}) },
    }
}

/**
 * Merge sparse saved global values with full defaults + system globals.
 * Order: DEFAULT_GLOBAL_VALUES → system globals → preset values → linked colors.
 *
 * Used by: listing card, preset editor, bot tab.
 */
export function mergeGlobalValues(
    presetGV: Partial<PresetGlobalValues> | null | undefined,
    systemGV: PresetGlobalValues | null | undefined,
    resolvedLinkedColors?: Record<string, string>
): PresetGlobalValues {
    const preset = presetGV || {}
    const system = systemGV || DEFAULT_GLOBAL_VALUES

    return {
        ...DEFAULT_GLOBAL_VALUES,
        ...system,
        ...preset,
        colors: {
            ...DEFAULT_GLOBAL_VALUES.colors,
            ...(system.colors || {}),
            ...(preset.colors || {}),
            ...(resolvedLinkedColors || {}),
        },
        typography: {
            ...DEFAULT_GLOBAL_VALUES.typography,
            ...(system.typography || {}),
            ...(preset.typography || {}),
            custom: preset.typography?.custom ?? system.typography?.custom ?? DEFAULT_GLOBAL_VALUES.typography?.custom ?? [],
        },
        ...((preset as any)?._links ? { _links: (preset as any)._links } : {}),
        ...((preset as any)?.effects ? { effects: (preset as any).effects } : {}),
        ...((preset as any)?.buttons ? { buttons: (preset as any).buttons } : {}),
        ...((preset as any)?.formFields ? { formFields: (preset as any).formFields } : {}),
        ...((preset as any)?.sizes ? { sizes: (preset as any).sizes } : {}),
        ...((preset as any)?.spacing ? { spacing: (preset as any).spacing } : {}),
    }
}

/**
 * Recursive merge: defaults under saved values.
 * Arrays are NOT merged — saved replaces default.
 * Only plain objects are recursively merged.
 */
export function deepMerge<T>(defaults: T, saved: Partial<T> | null | undefined): T {
    if (!defaults || typeof defaults !== 'object' || Array.isArray(defaults)) return (saved ?? defaults) as T
    if (!saved || typeof saved !== 'object' || Array.isArray(saved)) return (saved ?? defaults) as T

    const result: any = { ...defaults }
    for (const key of Object.keys(saved)) {
        const savedVal = (saved as any)[key]
        const defaultVal = (defaults as any)[key]
        if (
            savedVal && typeof savedVal === 'object' && !Array.isArray(savedVal) &&
            defaultVal && typeof defaultVal === 'object' && !Array.isArray(defaultVal)
        ) {
            result[key] = deepMerge(defaultVal, savedVal)
        } else {
            result[key] = savedVal
        }
    }
    return result as T
}

/**
 * Deep merge sparse saved widget settings with full defaults.
 * Each widget key gets its own recursive merge with DEFAULT_WIDGET_SETTINGS[key].
 *
 * PHP's merge_widget_settings_with_defaults() does this server-side via
 * array_replace_recursive. This is the client-side equivalent for defense
 * in depth (handles cases where data arrives without PHP merge).
 */
export function mergeWidgetSettings(
    saved: Partial<WidgetSettings> | null | undefined
): WidgetSettings {
    if (!saved) return { ...DEFAULT_WIDGET_SETTINGS }

    const result: any = { ...DEFAULT_WIDGET_SETTINGS }

    for (const key of Object.keys(DEFAULT_WIDGET_SETTINGS) as Array<keyof WidgetSettings>) {
        if (saved[key]) {
            result[key] = deepMerge(DEFAULT_WIDGET_SETTINGS[key], saved[key] as any)
        }
    }

    return result as WidgetSettings
}
