<?php

declare(strict_types=1);

namespace KimaAI\ChatBot;

defined('ABSPATH') || exit;

final class ChatbotTheme {

  public const DEFAULT_PRIMARY = '#4545f9';

  private const DEFAULT_THEME = [
    'version' => 2,
    'mode' => 'light',
    'style' => 'classic',
    'colorPreset' => 'default',
    'colors' => [
      'primary' => self::DEFAULT_PRIMARY,
      'accent' => '#818cf8',
      'surface' => '#ffffff',
      'neutral' => '#111827',
    ],
    'darkColors' => [
      'accent' => '#818cf8',
      'surface' => '#0f172a',
      'neutral' => '#f9fafb',
    ],
    'advanced' => [
      'bodyBackground' => null,
      'bodyText' => null,
      'headerBackground' => null,
      'headerText' => null,
      'aiMessageBackground' => null,
      'aiMessageText' => null,
      'userMessageBackground' => null,
      'userMessageText' => null,
      'inputBackground' => null,
      'inputText' => null,
      'footerBackground' => null,
      'footerText' => null,
      'border' => null,
    ],
  ];

  private const LEGACY_DEFAULTS = [
    'bodyBgColor' => self::DEFAULT_PRIMARY,
    'bodyTextColor' => '#ffffff',
    'userMessageBgColor' => self::DEFAULT_PRIMARY,
    'userMessageTextColor' => '#ffffff',
    'aiMessageBgColor' => '#f3f5ff',
    'aiMessageTextColor' => '#000000',
  ];

  private const VALID_MODES = ['light', 'dark', 'system'];

  /**
   * Returns the default chatbot theme configuration.
   *
   * @return array
   */
  public static function defaultTheme(): array {
    return self::DEFAULT_THEME;
  }

  /**
   * Returns the theme constants needed by the admin JS bundle.
   *
   * @return array
   */
  public static function jsConfig(): array {
    $style_defaults = [];
    foreach (self::styles() as $key => $style) {
      $style_defaults[$key] = [
        'colors' => $style['colors'] ?? null,
        'darkColors' => $style['darkColors'] ?? null,
      ];
    }

    return [
      'defaultTheme' => self::DEFAULT_THEME,
      'legacyDefaults' => self::LEGACY_DEFAULTS,
      'validModes' => self::VALID_MODES,
      'validStyles' => array_keys(self::styles()),
      'validColorPresets' => array_keys(self::colorPresets()),
      'styleDefaults' => $style_defaults,
    ];
  }

  /**
   * Returns the available chatbot color presets.
   *
   * @return array
   */
  public static function colorPresets(): array {
    $presets = [
      'default' => [
        'label' => __('Default', 'kimaai'),
        'colors' => self::DEFAULT_THEME['colors'],
      ],
      'custom' => [
        'label' => __('Custom', 'kimaai'),
        'colors' => null,
      ],
    ];

    return apply_filters('kimaai_chatbot_color_presets', $presets);
  }

  /**
   * Returns the available chatbot visual styles.
   *
   * @return array
   */
  public static function styles(): array {
    $styles = [
      'classic' => [
        'label' => __('Classic', 'kimaai'),
        'description' => __('Current KimaAI look and feel.', 'kimaai'),
        'colors' => ['primary' => '#4545f9', 'accent' => '#818cf8', 'surface' => '#ffffff', 'neutral' => '#111827'],
        'darkColors' => ['accent' => '#818cf8', 'surface' => '#0f172a', 'neutral' => '#f9fafb'],
      ],
      'minimalist' => [
        'label' => __('Minimalist', 'kimaai'),
        'description' => __('Reduced shadows, flatter surfaces, subtle borders.', 'kimaai'),
        'colors' => ['primary' => '#475569', 'accent' => '#94a3b8', 'surface' => '#f8fafc', 'neutral' => '#0f172a'],
        'darkColors' => ['accent' => '#94a3b8', 'surface' => '#020617', 'neutral' => '#f1f5f9'],
      ],
      'glossy' => [
        'label' => __('Glossy', 'kimaai'),
        'description' => __('Glass-like surfaces, stronger highlights, softer blur and shadow.', 'kimaai'),
        'colors' => ['primary' => '#6366f1', 'accent' => '#818cf8', 'surface' => '#f8f9ff', 'neutral' => '#312e81'],
        'darkColors' => ['accent' => '#818cf8', 'surface' => '#1e1b4b', 'neutral' => '#e0e7ff'],
      ],
      'neon' => [
        'label' => __('Neon', 'kimaai'),
        'description' => __('High-contrast accents with stronger glow effects.', 'kimaai'),
        'colors' => ['primary' => '#8b5cf6', 'accent' => '#c084fc', 'surface' => '#fafafa', 'neutral' => '#18181b'],
        'darkColors' => ['accent' => '#e879f9', 'surface' => '#09090b', 'neutral' => '#fafafa'],
      ],
    ];

    return apply_filters('kimaai_chatbot_theme_styles', $styles);
  }

  /**
   * Normalizes appearance settings into the shared theme contract.
   *
   * @param array $appearance Appearance settings.
   * @return array
   */
  public static function normalize(array $appearance): array {
    if (isset($appearance['theme']) && is_array($appearance['theme'])) {
      $theme = array_replace_recursive(self::defaultTheme(), $appearance['theme']);
    }
    else {
      $theme = self::fromLegacyAppearance($appearance);
    }

    if (self::shouldPreserveLegacyColors($appearance)) {
      $legacy_theme = self::fromLegacyAppearance($appearance);
      $theme['colors'] = array_replace($theme['colors'] ?? [], $legacy_theme['colors']);
      $theme['advanced'] = array_replace($theme['advanced'] ?? [], $legacy_theme['advanced']);
      $theme['colorPreset'] = $legacy_theme['colorPreset'];
    }

    $presets = self::colorPresets();
    $styles = self::styles();

    $theme['version'] = 2;
    $theme['mode'] = in_array($theme['mode'] ?? '', self::VALID_MODES, true) ? $theme['mode'] : self::DEFAULT_THEME['mode'];
    $theme['style'] = isset($styles[$theme['style'] ?? '']) ? $theme['style'] : self::DEFAULT_THEME['style'];
    $theme['colorPreset'] = isset($presets[$theme['colorPreset'] ?? '']) ? $theme['colorPreset'] : self::DEFAULT_THEME['colorPreset'];

    $theme['colors'] = self::normalizeColors($theme['colors'] ?? [], $theme['colorPreset'], $theme['style'], $presets, $styles);
    $theme['darkColors'] = self::normalizeDarkColors($theme['darkColors'] ?? [], $theme['colorPreset'], $theme['style'], $styles);
    $theme['advanced'] = self::normalizeAdvanced($theme['advanced'] ?? []);

    return $theme;
  }

  /**
   * Builds a version 2 theme from legacy appearance fields.
   *
   * @param array $appearance Legacy appearance settings.
   * @return array
   */
  public static function fromLegacyAppearance(array $appearance): array {
    $theme = self::defaultTheme();
    $has_custom_legacy_colors = false;

    foreach (self::LEGACY_DEFAULTS as $key => $default) {
      $value = self::stringOrNull($appearance[$key] ?? null);
      if ($value !== null && $value !== $default) {
        $has_custom_legacy_colors = true;
        break;
      }
    }

    $theme['colorPreset'] = $has_custom_legacy_colors ? 'custom' : 'default';
    $theme['colors']['primary'] = self::stringOrDefault($appearance['bodyBgColor'] ?? null, self::DEFAULT_THEME['colors']['primary']);
    $theme['colors']['neutral'] = self::stringOrDefault($appearance['aiMessageTextColor'] ?? null, self::DEFAULT_THEME['colors']['neutral']);

    $theme['advanced']['bodyBackground'] = self::stringOrNull($appearance['bodyBgColor'] ?? null);
    $theme['advanced']['bodyText'] = self::stringOrNull($appearance['bodyTextColor'] ?? null);
    $theme['advanced']['userMessageBackground'] = self::stringOrNull($appearance['userMessageBgColor'] ?? null);
    $theme['advanced']['userMessageText'] = self::stringOrNull($appearance['userMessageTextColor'] ?? null);
    $theme['advanced']['aiMessageBackground'] = self::stringOrNull($appearance['aiMessageBgColor'] ?? null);
    $theme['advanced']['aiMessageText'] = self::stringOrNull($appearance['aiMessageTextColor'] ?? null);

    return $theme;
  }

  /**
   * Builds the runtime CSS variable map for a theme.
   *
   * @param array $theme Normalized or partial theme configuration.
   * @return array
   */
  public static function cssVars(array $theme): array {
    $normalized_theme = self::normalize(['theme' => $theme]);
    $colors = $normalized_theme['colors'];
    $dark_colors = $normalized_theme['darkColors'];
    $advanced = $normalized_theme['advanced'];

    return [
      '--kimaai-chatbot-primary' => $colors['primary'],
      '--kimaai-chatbot-accent' => $colors['accent'],
      '--kimaai-chatbot-surface-base' => $colors['surface'],
      '--kimaai-chatbot-neutral-base' => $colors['neutral'],
      '--kimaai-chatbot-dark-surface-base' => $dark_colors['surface'],
      '--kimaai-chatbot-dark-neutral-base' => $dark_colors['neutral'],
      '--kimaai-chatbot-dark-accent' => $dark_colors['accent'],
      '--color-kimaai-chatbot-50' => 'color-mix(in oklch, var(--kimaai-chatbot-primary) 7%, var(--kimaai-white))',
      '--color-kimaai-chatbot-100' => 'color-mix(in oklch, var(--kimaai-chatbot-primary) 20%, var(--kimaai-white))',
      '--color-kimaai-chatbot-200' => 'color-mix(in oklch, var(--kimaai-chatbot-primary) 30%, var(--kimaai-white))',
      '--color-kimaai-chatbot-300' => 'color-mix(in oklch, var(--kimaai-chatbot-primary) 50%, var(--kimaai-white))',
      '--color-kimaai-chatbot-400' => 'color-mix(in oklch, var(--kimaai-chatbot-primary) 70%, var(--kimaai-white))',
      '--color-kimaai-chatbot-500' => 'var(--kimaai-chatbot-primary)',
      '--color-kimaai-chatbot-600' => 'color-mix(in oklch, var(--kimaai-chatbot-primary) 90%, var(--kimaai-dark))',
      '--color-kimaai-chatbot-700' => 'color-mix(in oklch, var(--kimaai-chatbot-primary) 80%, var(--kimaai-dark))',
      '--color-kimaai-chatbot-800' => 'color-mix(in oklch, var(--kimaai-chatbot-primary) 70%, var(--kimaai-dark))',
      '--color-kimaai-chatbot-900' => 'color-mix(in oklch, var(--kimaai-chatbot-primary) 30%, var(--kimaai-dark))',
      '--kimaai-chatbot-body-override' => $advanced['bodyBackground'],
      '--kimaai-chatbot-text-override' => $advanced['bodyText'],
      '--kimaai-chatbot-header-background-override' => $advanced['headerBackground'],
      '--kimaai-chatbot-header-text-override' => $advanced['headerText'],
      '--kimaai-chatbot-ai-message-background-override' => $advanced['aiMessageBackground'],
      '--kimaai-chatbot-ai-message-text-override' => $advanced['aiMessageText'],
      '--kimaai-chatbot-user-message-background-override' => $advanced['userMessageBackground'],
      '--kimaai-chatbot-user-message-text-override' => $advanced['userMessageText'],
      '--kimaai-chatbot-input-background-override' => $advanced['inputBackground'],
      '--kimaai-chatbot-input-text-override' => $advanced['inputText'],
      '--kimaai-chatbot-footer-background-override' => $advanced['footerBackground'],
      '--kimaai-chatbot-footer-text-override' => $advanced['footerText'],
      '--kimaai-chatbot-border-color-override' => $advanced['border'],
      '--kimaai-chatbot-body' => 'var(--kimaai-chatbot-body-override, var(--kimaai-chatbot-body-default))',
      '--kimaai-chatbot-text' => 'var(--kimaai-chatbot-text-override, var(--kimaai-chatbot-text-default))',
      '--kimaai-chatbot-header-background' => 'var(--kimaai-chatbot-header-background-override, var(--kimaai-chatbot-header-background-default))',
      '--kimaai-chatbot-header-text' => 'var(--kimaai-chatbot-header-text-override, var(--kimaai-chatbot-header-text-default))',
      '--kimaai-chatbot-user-message-background' => 'var(--kimaai-chatbot-user-message-background-override, var(--kimaai-chatbot-user-message-background-default))',
      '--kimaai-chatbot-user-message-text' => 'var(--kimaai-chatbot-user-message-text-override, var(--kimaai-chatbot-user-message-text-default))',
      '--kimaai-chatbot-ai-message-background' => 'var(--kimaai-chatbot-ai-message-background-override, var(--kimaai-chatbot-ai-message-background-default))',
      '--kimaai-chatbot-ai-message-text' => 'var(--kimaai-chatbot-ai-message-text-override, var(--kimaai-chatbot-ai-message-text-default))',
      '--kimaai-chatbot-input-background' => 'var(--kimaai-chatbot-input-background-override, var(--kimaai-chatbot-input-background-default))',
      '--kimaai-chatbot-input-text' => 'var(--kimaai-chatbot-input-text-override, var(--kimaai-chatbot-input-text-default))',
      '--kimaai-chatbot-footer-background' => 'var(--kimaai-chatbot-footer-background-override, var(--kimaai-chatbot-footer-background-default))',
      '--kimaai-chatbot-footer-text' => 'var(--kimaai-chatbot-footer-text-override, var(--kimaai-chatbot-footer-text-default))',
      '--kimaai-chatbot-border-color' => 'var(--kimaai-chatbot-border-color-override, var(--kimaai-chatbot-border-color-default))',
    ];
  }

  /**
   * Returns data attributes for the chatbot mount point.
   *
   * @param array $theme Theme configuration.
   * @return array
   */
  public static function rootAttributes(array $theme): array {
    $normalized_theme = self::normalize(['theme' => $theme]);

    return [
      'data-kimaai-mode' => $normalized_theme['mode'],
      'data-kimaai-style' => $normalized_theme['style'],
      'data-kimaai-color-preset' => $normalized_theme['colorPreset'],
    ];
  }

  /**
   * Normalizes theme seed colors.
   *
   * @param array $colors Saved colors.
   * @param string $color_preset Saved preset name.
   * @param array $presets Available presets.
   * @return array
   */
  private static function normalizeColors(array $colors, string $color_preset, string $style, array $presets, array $styles): array {
    $default_colors = self::DEFAULT_THEME['colors'];

    if ($color_preset === 'default') {
      $style_colors = $styles[$style]['colors'] ?? null;
      if (is_array($style_colors)) {
        $colors = $style_colors;
      }
      else {
        $preset_colors = $presets[$color_preset]['colors'] ?? null;
        if (is_array($preset_colors)) {
          $colors = $preset_colors;
        }
      }
    }

    $normalized = [];
    foreach ($default_colors as $key => $default) {
      $normalized[$key] = self::stringOrDefault($colors[$key] ?? null, $default);
    }

    return $normalized;
  }

  /**
   * Normalizes dark-mode seed colors (accent, surface, neutral).
   *
   * @param array $dark_colors Saved dark colors.
   * @param string $color_preset Saved preset name.
   * @param string $style Saved style key.
   * @param array $styles Available styles.
   * @return array
   */
  private static function normalizeDarkColors(array $dark_colors, string $color_preset, string $style, array $styles): array {
    $default_dark = self::DEFAULT_THEME['darkColors'];

    if ($color_preset === 'default') {
      $style_dark = $styles[$style]['darkColors'] ?? null;
      if (is_array($style_dark)) {
        $dark_colors = $style_dark;
      }
      else {
        $dark_colors = $default_dark;
      }
    }

    $normalized = [];
    foreach ($default_dark as $key => $default) {
      $normalized[$key] = self::stringOrDefault($dark_colors[$key] ?? null, $default);
    }

    return $normalized;
  }

  /**
   * Normalizes advanced per-component overrides.
   *
   * @param array $advanced Saved advanced values.
   * @return array
   */
  private static function normalizeAdvanced(array $advanced): array {
    $normalized = [];

    foreach (self::DEFAULT_THEME['advanced'] as $key => $default) {
      $normalized[$key] = self::stringOrNull($advanced[$key] ?? $default);
    }

    return $normalized;
  }

  /**
   * Returns whether legacy color settings should backfill the default theme object.
   *
   * @param array $appearance Appearance settings.
   * @return bool
   */
  private static function shouldPreserveLegacyColors(array $appearance): bool {
    if (!isset($appearance['theme']) || !is_array($appearance['theme']) || !self::hasCustomLegacyColors($appearance)) {
      return false;
    }

    $saved_theme = $appearance['theme'];
    $saved_colors = is_array($saved_theme['colors'] ?? null) ? $saved_theme['colors'] : [];
    $saved_advanced = is_array($saved_theme['advanced'] ?? null) ? $saved_theme['advanced'] : [];

    return !self::hasCustomThemeColors($saved_colors) && !self::hasAdvancedOverrides($saved_advanced);
  }

  /**
   * Returns whether any legacy appearance color differs from its legacy default.
   *
   * @param array $appearance Appearance settings.
   * @return bool
   */
  private static function hasCustomLegacyColors(array $appearance): bool {
    foreach (self::LEGACY_DEFAULTS as $key => $default) {
      $value = self::stringOrNull($appearance[$key] ?? null);
      if ($value !== null && $value !== $default) {
        return true;
      }
    }

    return false;
  }

  /**
   * Returns whether the saved theme contains custom seed colors.
   *
   * @param array $colors Saved theme colors.
   * @return bool
   */
  private static function hasCustomThemeColors(array $colors): bool {
    foreach (self::DEFAULT_THEME['colors'] as $key => $default) {
      $value = self::stringOrNull($colors[$key] ?? null);
      if ($value !== null && $value !== $default) {
        return true;
      }
    }

    return false;
  }

  /**
   * Returns whether the saved theme contains advanced overrides.
   *
   * @param array $advanced Saved advanced overrides.
   * @return bool
   */
  private static function hasAdvancedOverrides(array $advanced): bool {
    foreach (self::DEFAULT_THEME['advanced'] as $key => $default) {
      $value = self::stringOrNull($advanced[$key] ?? $default);
      if ($value !== null) {
        return true;
      }
    }

    return false;
  }

  /**
   * Returns the normalized string value or a fallback.
   *
   * @param mixed $value Raw value.
   * @param string $fallback Fallback string.
   * @return string
   */
  private static function stringOrDefault(mixed $value, string $fallback): string {
    $normalized = self::stringOrNull($value);

    return $normalized ?? $fallback;
  }

  /**
   * Returns a trimmed string value or null when empty.
   *
   * @param mixed $value Raw value.
   * @return string|null
   */
  private static function stringOrNull(mixed $value): ?string {
    if (!is_string($value)) {
      return null;
    }

    $value = trim($value);

    return $value === '' ? null : $value;
  }
}
