import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import 'app_palette.dart';

enum AppThemeSurface { desktop, web, mobile }

AppThemeSurface resolveAppThemeSurface({
  TargetPlatform? platform,
  bool isWeb = kIsWeb,
}) {
  if (isWeb) {
    return AppThemeSurface.web;
  }
  final resolvedPlatform = platform ?? defaultTargetPlatform;
  if (resolvedPlatform == TargetPlatform.iOS ||
      resolvedPlatform == TargetPlatform.android) {
    return AppThemeSurface.mobile;
  }
  return AppThemeSurface.desktop;
}

// Default theme token set: simple
class SimpleSpacing {
  SimpleSpacing._();

  static const double page = 0.0;
  static const double compact = 6.0;
  static const double section = 8.0;
  static const double xxs = 4.0;
  static const double xs = compact;
  static const double sm = section;
  static const double md = section;
  static const double lg = section;
  static const double xl = 12.0;
}

class SimpleRadius {
  SimpleRadius._();

  static const double card = 12.0;
  static const double button = 12.0;
  static const double input = 12.0;
  static const double chip = 12.0;
  static const double badge = 12.0;
  static const double dialog = 12.0;
  static const double sidebar = 12.0;
  static const double icon = 12.0;
}

class SimpleTypography {
  SimpleTypography._();

  static const double displaySize = 28.0;
  static const FontWeight displayWeight = FontWeight.w700;
  static const double displayHeight = 32 / 28;

  static const double titleSize = 20.0;
  static const FontWeight titleWeight = FontWeight.w600;
  static const double titleHeight = 24 / 20;

  static const double sectionSize = 13.0;
  static const FontWeight sectionWeight = FontWeight.w600;
  static const double sectionHeight = 14 / 13;

  static const double bodySize = 13.0;
  static const FontWeight bodyWeight = FontWeight.w400;
  static const double bodyHeight = 15 / 13;

  static const double compactBodySize = 13.0;
  static const FontWeight compactBodyWeight = FontWeight.w400;
  static const double compactBodyHeight = 15 / 13;

  static const double emphasizedBodySize = 13.0;
  static const FontWeight emphasizedBodyWeight = FontWeight.w600;
  static const double emphasizedBodyHeight = 14 / 13;

  static const double captionSize = 12.0;
  static const FontWeight captionWeight = FontWeight.w400;
  static const double captionHeight = 16 / 12;
}

class SimpleSizes {
  SimpleSizes._();

  static const double sidebarItemHeight = 32.0;
  static const double sidebarIconSize = 18.0;
  static const double sidebarTextSize = 13.0;
  static const double sidebarExpandedWidthZh = 152.0;
  static const double sidebarExpandedWidthEn = 188.0;
  static const double sidebarExpandedWidth = sidebarExpandedWidthZh;
  static const double sidebarCollapsedWidth = 56.0;

  static const double textareaHeight = 36.0;
  static const double toolbarHeight = 40.0;

  static const double inputHeight = 40.0;
  static const double buttonHeightDesktop = 30.0;
  static const double buttonHeightMobile = 36.0;
}

class AppSpacing {
  AppSpacing._();

  static const double page = SimpleSpacing.page;
  static const double compact = SimpleSpacing.compact;
  static const double section = SimpleSpacing.section;
  static const double xxs = SimpleSpacing.xxs;
  static const double xs = SimpleSpacing.xs;
  static const double sm = SimpleSpacing.sm;
  static const double md = SimpleSpacing.md;
  static const double lg = SimpleSpacing.lg;
  static const double xl = SimpleSpacing.xl;
}

class AppRadius {
  AppRadius._();

  static const double card = SimpleRadius.card;
  static const double button = SimpleRadius.button;
  static const double input = SimpleRadius.input;
  static const double chip = SimpleRadius.chip;
  static const double badge = SimpleRadius.badge;
  static const double dialog = SimpleRadius.dialog;
  static const double sidebar = SimpleRadius.sidebar;
  static const double icon = SimpleRadius.icon;
}

class AppTypography {
  AppTypography._();

  static const double displaySize = SimpleTypography.displaySize;
  static const FontWeight displayWeight = SimpleTypography.displayWeight;
  static const double displayHeight = SimpleTypography.displayHeight;

  static const double titleSize = SimpleTypography.titleSize;
  static const FontWeight titleWeight = SimpleTypography.titleWeight;
  static const double titleHeight = SimpleTypography.titleHeight;

  static const double sectionSize = SimpleTypography.sectionSize;
  static const FontWeight sectionWeight = SimpleTypography.sectionWeight;
  static const double sectionHeight = SimpleTypography.sectionHeight;

  static const double bodySize = SimpleTypography.bodySize;
  static const FontWeight bodyWeight = SimpleTypography.bodyWeight;
  static const double bodyHeight = SimpleTypography.bodyHeight;

  static const double compactBodySize = SimpleTypography.compactBodySize;
  static const FontWeight compactBodyWeight =
      SimpleTypography.compactBodyWeight;
  static const double compactBodyHeight = SimpleTypography.compactBodyHeight;

  static const double emphasizedBodySize = SimpleTypography.emphasizedBodySize;
  static const FontWeight emphasizedBodyWeight =
      SimpleTypography.emphasizedBodyWeight;
  static const double emphasizedBodyHeight =
      SimpleTypography.emphasizedBodyHeight;

  static const double captionSize = SimpleTypography.captionSize;
  static const FontWeight captionWeight = SimpleTypography.captionWeight;
  static const double captionHeight = SimpleTypography.captionHeight;
}

class AppSizes {
  AppSizes._();

  static const double sidebarItemHeight = SimpleSizes.sidebarItemHeight;
  static const double sidebarIconSize = SimpleSizes.sidebarIconSize;
  static const double sidebarTextSize = SimpleSizes.sidebarTextSize;
  static const double sidebarExpandedWidthZh =
      SimpleSizes.sidebarExpandedWidthZh;
  static const double sidebarExpandedWidthEn =
      SimpleSizes.sidebarExpandedWidthEn;
  static const double sidebarExpandedWidth = SimpleSizes.sidebarExpandedWidth;
  static const double sidebarCollapsedWidth = SimpleSizes.sidebarCollapsedWidth;

  static const double textareaHeight = SimpleSizes.textareaHeight;
  static const double toolbarHeight = SimpleSizes.toolbarHeight;

  static const double inputHeight = SimpleSizes.inputHeight;
  static const double buttonHeightDesktop = SimpleSizes.buttonHeightDesktop;
  static const double buttonHeightMobile = SimpleSizes.buttonHeightMobile;
}

class AppTheme {
  static ThemeData light({
    TargetPlatform? platform,
    AppThemeSurface? surface,
  }) => _theme(
    brightness: Brightness.light,
    palette: AppPalette.light,
    platform: platform,
    surface: surface,
  );

  static ThemeData dark({
    TargetPlatform? platform,
    AppThemeSurface? surface,
  }) => _theme(
    brightness: Brightness.dark,
    palette: AppPalette.dark,
    platform: platform,
    surface: surface,
  );

  static ThemeData _theme({
    required Brightness brightness,
    required AppPalette palette,
    TargetPlatform? platform,
    AppThemeSurface? surface,
  }) {
    final resolvedPlatform = platform ?? defaultTargetPlatform;
    final resolvedSurface =
        surface ?? resolveAppThemeSurface(platform: resolvedPlatform);
    final scene = _AppThemeSceneConfig.fromSurface(resolvedSurface);
    final colorScheme =
        ColorScheme.fromSeed(
          seedColor: palette.accent,
          brightness: brightness,
          surface: palette.surfacePrimary,
        ).copyWith(
          primary: palette.accent,
          onPrimary: Colors.white,
          secondary: palette.accent,
          onSecondary: Colors.white,
          tertiary: palette.success,
          onTertiary: Colors.white,
          error: palette.danger,
          onError: Colors.white,
          surface: palette.surfacePrimary,
          onSurface: palette.textPrimary,
          surfaceContainerHighest: palette.surfaceSecondary,
          outline: palette.stroke,
          outlineVariant: palette.strokeSoft,
          inverseSurface: palette.textPrimary,
          onInverseSurface: palette.surfacePrimary,
          shadow: palette.shadow,
          scrim: Colors.black.withValues(
            alpha: brightness == Brightness.dark ? 0.62 : 0.12,
          ),
        );

    final base = ThemeData(
      useMaterial3: true,
      brightness: brightness,
      typography: Typography.material2021(platform: resolvedPlatform),
      colorScheme: colorScheme,
      scaffoldBackgroundColor: palette.canvas,
      extensions: [palette],
    );
    final tunedTextTheme = _textTheme(
      base.textTheme,
      palette: palette,
      useCompactDisplay: scene.useCompactDisplay,
    );

    return base.copyWith(
      platform: resolvedPlatform,
      splashFactory: NoSplash.splashFactory,
      materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
      visualDensity: scene.visualDensity,
      dividerColor: palette.strokeSoft,
      hoverColor: palette.hover,
      textTheme: tunedTextTheme,
      primaryTextTheme: tunedTextTheme,
      appBarTheme: const AppBarTheme(
        backgroundColor: Colors.transparent,
        elevation: 0,
        scrolledUnderElevation: 0,
        surfaceTintColor: Colors.transparent,
      ),
      cardTheme: CardThemeData(
        elevation: 0,
        color: palette.surfacePrimary,
        margin: EdgeInsets.zero,
        shadowColor: palette.shadow,
        surfaceTintColor: Colors.transparent,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(AppRadius.card),
          side: BorderSide(color: palette.strokeSoft),
        ),
      ),
      chipTheme: base.chipTheme.copyWith(
        backgroundColor: palette.surfaceSecondary,
        selectedColor: palette.surfacePrimary,
        secondarySelectedColor: palette.surfacePrimary,
        disabledColor: palette.surfaceSecondary,
        side: BorderSide(color: palette.strokeSoft),
        checkmarkColor: Colors.transparent,
        labelStyle: tunedTextTheme.labelMedium,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(AppRadius.chip),
        ),
        padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
      ),
      filledButtonTheme: FilledButtonThemeData(
        style: ButtonStyle(
          foregroundColor: const WidgetStatePropertyAll(Colors.white),
          shadowColor: WidgetStatePropertyAll(palette.shadow),
          elevation: const WidgetStatePropertyAll(0),
          surfaceTintColor: const WidgetStatePropertyAll(Colors.transparent),
          textStyle: WidgetStatePropertyAll(
            tunedTextTheme.labelLarge?.copyWith(fontWeight: FontWeight.w600),
          ),
          minimumSize: WidgetStatePropertyAll(
            Size(
              0,
              scene.buttonHeight,
            ),
          ),
          padding: const WidgetStatePropertyAll(
            EdgeInsets.symmetric(horizontal: 12, vertical: 0),
          ),
          shape: WidgetStatePropertyAll(
            RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(AppRadius.button),
            ),
          ),
          backgroundColor: WidgetStateProperty.resolveWith((states) {
            if (states.contains(WidgetState.pressed)) {
              return palette.accentHover;
            }
            return palette.accent;
          }),
        ),
      ),
      outlinedButtonTheme: OutlinedButtonThemeData(
        style: OutlinedButton.styleFrom(
          backgroundColor: palette.surfaceSecondary,
          foregroundColor: palette.textPrimary,
          shadowColor: palette.shadow,
          elevation: 0,
          surfaceTintColor: Colors.transparent,
          textStyle: tunedTextTheme.labelLarge?.copyWith(
            fontWeight: FontWeight.w600,
          ),
          minimumSize: Size(
            0,
            scene.buttonHeight,
          ),
          padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 0),
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(AppRadius.button),
          ),
          side: BorderSide(color: palette.strokeSoft),
        ),
      ),
      textButtonTheme: TextButtonThemeData(
        style: TextButton.styleFrom(
          foregroundColor: palette.textPrimary,
          textStyle: tunedTextTheme.labelLarge?.copyWith(
            fontWeight: FontWeight.w500,
          ),
          minimumSize: Size(
            0,
            scene.buttonHeight,
          ),
          padding: const EdgeInsets.symmetric(
            horizontal: AppSpacing.sm,
            vertical: 0,
          ),
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(AppRadius.button),
          ),
        ),
      ),
      iconButtonTheme: IconButtonThemeData(
        style: IconButton.styleFrom(
          foregroundColor: palette.textSecondary,
          backgroundColor: palette.surfacePrimary.withValues(alpha: 0.94),
          surfaceTintColor: Colors.transparent,
          minimumSize: const Size(32, 32),
          padding: const EdgeInsets.all(7),
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(AppRadius.icon),
          ),
        ),
      ),
      inputDecorationTheme: InputDecorationTheme(
        isDense: true,
        filled: true,
        fillColor: palette.surfacePrimary,
        hintStyle: tunedTextTheme.bodyMedium?.copyWith(
          color: palette.textMuted,
        ),
        labelStyle: tunedTextTheme.bodyMedium?.copyWith(
          color: palette.textMuted,
        ),
        floatingLabelStyle: tunedTextTheme.bodyMedium?.copyWith(
          color: palette.textSecondary,
        ),
        contentPadding: const EdgeInsets.symmetric(
          horizontal: AppSpacing.sm,
          vertical: AppSpacing.compact,
        ),
        constraints: const BoxConstraints(minHeight: AppSizes.inputHeight),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(AppRadius.input),
          borderSide: BorderSide(color: palette.strokeSoft),
        ),
        enabledBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(AppRadius.input),
          borderSide: BorderSide(color: palette.strokeSoft),
        ),
        focusedBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(AppRadius.input),
          borderSide: BorderSide(color: palette.accent.withValues(alpha: 0.32)),
        ),
      ),
      segmentedButtonTheme: SegmentedButtonThemeData(
        style: ButtonStyle(
          side: const WidgetStatePropertyAll(BorderSide.none),
          backgroundColor: WidgetStateProperty.resolveWith((states) {
            if (states.contains(WidgetState.selected)) {
              return palette.surfacePrimary.withValues(alpha: 0.96);
            }
            return palette.surfaceSecondary;
          }),
          foregroundColor: WidgetStateProperty.resolveWith((states) {
            if (states.contains(WidgetState.selected)) {
              return palette.textPrimary;
            }
            return palette.textSecondary;
          }),
          padding: const WidgetStatePropertyAll(
            EdgeInsets.symmetric(
              horizontal: AppSpacing.sm,
              vertical: AppSpacing.compact,
            ),
          ),
          shape: WidgetStatePropertyAll(
            RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(AppRadius.chip),
            ),
          ),
          textStyle: WidgetStatePropertyAll(
            tunedTextTheme.labelLarge?.copyWith(fontWeight: FontWeight.w500),
          ),
        ),
      ),
      snackBarTheme: SnackBarThemeData(
        behavior: SnackBarBehavior.floating,
        backgroundColor: palette.surfacePrimary.withValues(alpha: 0.96),
        contentTextStyle: TextStyle(color: palette.textPrimary),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(AppRadius.dialog),
        ),
      ),
      popupMenuTheme: PopupMenuThemeData(
        color: palette.surfacePrimary.withValues(alpha: 0.98),
        surfaceTintColor: Colors.transparent,
        elevation: 0,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(AppRadius.dialog),
        ),
      ),
    );
  }

  static TextTheme _textTheme(
    TextTheme base, {
    required AppPalette palette,
    required bool useCompactDisplay,
  }) {
    TextStyle withUiFont(TextStyle? style) {
      return (style ?? const TextStyle()).copyWith(
        fontFamily: null,
        fontFamilyFallback: const <String>[],
        package: null,
      );
    }

    return base.copyWith(
      displaySmall: withUiFont(
        base.displaySmall?.copyWith(
          fontSize: useCompactDisplay ? 24 : AppTypography.displaySize,
          fontWeight: AppTypography.displayWeight,
          letterSpacing: useCompactDisplay ? -0.24 : -0.32,
          height: useCompactDisplay ? 28 / 24 : AppTypography.displayHeight,
          color: palette.textPrimary,
        ),
      ),
      headlineSmall: withUiFont(
        base.headlineSmall?.copyWith(
          fontSize: AppTypography.titleSize,
          fontWeight: AppTypography.titleWeight,
          letterSpacing: -0.18,
          height: AppTypography.titleHeight,
          color: palette.textPrimary,
        ),
      ),
      titleLarge: withUiFont(
        base.titleLarge?.copyWith(
          fontSize: AppTypography.sectionSize,
          fontWeight: FontWeight.w600,
          letterSpacing: 0.02,
          height: AppTypography.sectionHeight,
          color: palette.textPrimary,
        ),
      ),
      titleMedium: withUiFont(
        base.titleMedium?.copyWith(
          fontSize: AppTypography.sectionSize,
          fontWeight: AppTypography.sectionWeight,
          letterSpacing: 0,
          height: AppTypography.sectionHeight,
          color: palette.textPrimary,
        ),
      ),
      titleSmall: withUiFont(
        base.titleSmall?.copyWith(
          fontSize: AppTypography.compactBodySize,
          fontWeight: FontWeight.w600,
          height: AppTypography.compactBodyHeight,
          color: palette.textPrimary,
        ),
      ),
      bodyLarge: withUiFont(
        base.bodyLarge?.copyWith(
          fontSize: AppTypography.bodySize,
          fontWeight: AppTypography.bodyWeight,
          height: AppTypography.bodyHeight,
          color: palette.textPrimary,
        ),
      ),
      bodyMedium: withUiFont(
        base.bodyMedium?.copyWith(
          fontSize: AppTypography.compactBodySize,
          fontWeight: AppTypography.compactBodyWeight,
          height: AppTypography.compactBodyHeight,
          color: palette.textSecondary,
        ),
      ),
      bodySmall: withUiFont(
        base.bodySmall?.copyWith(
          fontSize: AppTypography.captionSize,
          fontWeight: AppTypography.captionWeight,
          height: AppTypography.captionHeight,
          color: palette.textMuted,
        ),
      ),
      labelLarge: withUiFont(
        base.labelLarge?.copyWith(
          fontSize: AppTypography.emphasizedBodySize,
          fontWeight: AppTypography.emphasizedBodyWeight,
          height: AppTypography.emphasizedBodyHeight,
          color: palette.textPrimary,
        ),
      ),
      labelMedium: withUiFont(
        base.labelMedium?.copyWith(
          fontSize: AppTypography.captionSize,
          fontWeight: FontWeight.w600,
          letterSpacing: 0.2,
          height: AppTypography.captionHeight,
          color: palette.textSecondary,
        ),
      ),
      labelSmall: withUiFont(
        base.labelSmall?.copyWith(
          fontSize: AppTypography.captionSize,
          fontWeight: FontWeight.w400,
          height: AppTypography.captionHeight,
          color: palette.textMuted,
        ),
      ),
    );
  }
}

class _AppThemeSceneConfig {
  const _AppThemeSceneConfig({
    required this.visualDensity,
    required this.buttonHeight,
    required this.useCompactDisplay,
  });

  final VisualDensity visualDensity;
  final double buttonHeight;
  final bool useCompactDisplay;

  factory _AppThemeSceneConfig.fromSurface(AppThemeSurface surface) {
    return switch (surface) {
      AppThemeSurface.desktop => const _AppThemeSceneConfig(
        visualDensity: VisualDensity(horizontal: -1, vertical: -1),
        buttonHeight: AppSizes.buttonHeightDesktop,
        useCompactDisplay: false,
      ),
      AppThemeSurface.web => const _AppThemeSceneConfig(
        visualDensity: VisualDensity(horizontal: -1, vertical: -1),
        buttonHeight: AppSizes.buttonHeightDesktop,
        useCompactDisplay: false,
      ),
      AppThemeSurface.mobile => const _AppThemeSceneConfig(
        visualDensity: VisualDensity.standard,
        buttonHeight: AppSizes.buttonHeightMobile,
        useCompactDisplay: true,
      ),
    };
  }
}
