import 'package:flutter/material.dart';

const _radius = 6.0;
const _badgeRadius = 5.0;

@immutable
final class CourtBlazerTokens extends ThemeExtension<CourtBlazerTokens> {
  const CourtBlazerTokens({
    required this.accent,
    required this.border,
    required this.mutedText,
    required this.success,
  });

  final Color accent;
  final Color border;
  final Color mutedText;
  final Color success;

  @override
  CourtBlazerTokens copyWith({
    Color? accent,
    Color? border,
    Color? mutedText,
    Color? success,
  }) {
    return CourtBlazerTokens(
      accent: accent ?? this.accent,
      border: border ?? this.border,
      mutedText: mutedText ?? this.mutedText,
      success: success ?? this.success,
    );
  }

  @override
  CourtBlazerTokens lerp(ThemeExtension<CourtBlazerTokens>? other, double t) {
    if (other is! CourtBlazerTokens) return this;
    return CourtBlazerTokens(
      accent: Color.lerp(accent, other.accent, t)!,
      border: Color.lerp(border, other.border, t)!,
      mutedText: Color.lerp(mutedText, other.mutedText, t)!,
      success: Color.lerp(success, other.success, t)!,
    );
  }
}

final class AppTextStyles {
  const AppTextStyles._();

  static TextStyle scoreNumber(BuildContext context) {
    return Theme.of(context).textTheme.displaySmall!.copyWith(
      fontFeatures: const [FontFeature.tabularFigures()],
    );
  }

  static TextStyle timer(BuildContext context) {
    return Theme.of(context).textTheme.displayLarge!.copyWith(
      fontFeatures: const [FontFeature.tabularFigures()],
    );
  }
}

CourtBlazerTokens courtBlazerTokensOf(BuildContext context) {
  final theme = Theme.of(context);
  return theme.extension<CourtBlazerTokens>() ??
      CourtBlazerTokens(
        accent: theme.colorScheme.secondary,
        border: theme.dividerColor,
        mutedText: theme.colorScheme.onSurfaceVariant,
        success: Colors.green,
      );
}

ThemeData courtBlazerLightTheme() {
  return _courtBlazerTheme(
    brightness: Brightness.light,
    primary: const Color(0xFF9E7623),
    accent: const Color(0xFFB91C2B),
    background: const Color(0xFFF4F1EA),
    surface: Colors.white,
    text: const Color(0xFF11131A),
    mutedText: const Color(0xFF626A78),
    border: const Color(0xFFE4DFD2),
    success: const Color(0xFF178A4A),
    error: const Color(0xFFC81E32),
  );
}

ThemeData courtBlazerDarkTheme() {
  return _courtBlazerTheme(
    brightness: Brightness.dark,
    primary: const Color(0xFFC9A24A),
    accent: const Color(0xFFD72638),
    background: const Color(0xFF080A12),
    surface: const Color(0xFF141824),
    text: const Color(0xFFF5F1E8),
    mutedText: const Color(0xFFA7ADBA),
    border: const Color(0xFF242A3A),
    success: const Color(0xFF2ECC71),
    error: const Color(0xFFFF4D5E),
  );
}

ThemeData _courtBlazerTheme({
  required Brightness brightness,
  required Color primary,
  required Color accent,
  required Color background,
  required Color surface,
  required Color text,
  required Color mutedText,
  required Color border,
  required Color success,
  required Color error,
}) {
  final colorScheme = ColorScheme(
    brightness: brightness,
    primary: primary,
    onPrimary: brightness == Brightness.dark ? background : surface,
    secondary: accent,
    onSecondary: surface,
    error: error,
    onError: surface,
    surface: surface,
    onSurface: text,
  );
  final baseTextTheme = _textTheme(text, mutedText);
  final roundedBorder = RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(_radius),
    side: BorderSide(color: border),
  );

  return ThemeData(
    useMaterial3: true,
    brightness: brightness,
    colorScheme: colorScheme,
    scaffoldBackgroundColor: background,
    fontFamily: 'Archivo',
    textTheme: baseTextTheme,
    appBarTheme: AppBarTheme(
      centerTitle: false,
      elevation: 0,
      scrolledUnderElevation: 0,
      backgroundColor: background,
      foregroundColor: text,
      titleTextStyle: baseTextTheme.titleLarge,
    ),
    cardTheme: CardThemeData(
      elevation: 0,
      color: surface,
      surfaceTintColor: Colors.transparent,
      shape: roundedBorder,
      margin: EdgeInsets.zero,
    ),
    chipTheme: ChipThemeData(
      backgroundColor: surface,
      selectedColor: primary.withAlpha(41),
      disabledColor: border,
      labelStyle: baseTextTheme.labelMedium,
      secondaryLabelStyle: baseTextTheme.labelMedium,
      side: BorderSide(color: border),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(_badgeRadius),
      ),
    ),
    dividerTheme: DividerThemeData(color: border, thickness: 1),
    inputDecorationTheme: InputDecorationTheme(
      filled: true,
      fillColor: surface,
      border: _inputBorder(border),
      enabledBorder: _inputBorder(border),
      focusedBorder: _inputBorder(primary, width: 1.5),
      errorBorder: _inputBorder(error),
    ),
    filledButtonTheme: FilledButtonThemeData(
      style: FilledButton.styleFrom(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(_radius),
        ),
        textStyle: baseTextTheme.labelLarge,
      ),
    ),
    outlinedButtonTheme: OutlinedButtonThemeData(
      style: OutlinedButton.styleFrom(
        side: BorderSide(color: border),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(_radius),
        ),
        textStyle: baseTextTheme.labelLarge,
      ),
    ),
    textButtonTheme: TextButtonThemeData(
      style: TextButton.styleFrom(textStyle: baseTextTheme.labelLarge),
    ),
    floatingActionButtonTheme: FloatingActionButtonThemeData(
      elevation: 0,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(_radius),
      ),
    ),
    listTileTheme: ListTileThemeData(
      iconColor: mutedText,
      titleTextStyle: baseTextTheme.titleSmall,
      subtitleTextStyle: baseTextTheme.bodyMedium?.copyWith(color: mutedText),
    ),
    bannerTheme: MaterialBannerThemeData(
      backgroundColor: surface,
      dividerColor: Colors.transparent,
      contentTextStyle: baseTextTheme.bodyMedium,
    ),
    extensions: [
      CourtBlazerTokens(
        accent: accent,
        border: border,
        mutedText: mutedText,
        success: success,
      ),
    ],
  );
}

TextTheme _textTheme(Color text, Color mutedText) {
  const anton = 'Anton';
  const archivo = 'Archivo';
  return TextTheme(
    displayLarge: TextStyle(
      fontFamily: anton,
      fontSize: 56,
      height: 1,
      color: text,
    ),
    displayMedium: TextStyle(
      fontFamily: anton,
      fontSize: 44,
      height: 1.05,
      color: text,
    ),
    displaySmall: TextStyle(
      fontFamily: anton,
      fontSize: 34,
      height: 1.05,
      color: text,
    ),
    headlineLarge: TextStyle(
      fontFamily: anton,
      fontSize: 32,
      height: 1.1,
      color: text,
    ),
    headlineMedium: TextStyle(
      fontFamily: anton,
      fontSize: 28,
      height: 1.1,
      color: text,
    ),
    headlineSmall: TextStyle(
      fontFamily: anton,
      fontSize: 24,
      height: 1.15,
      color: text,
    ),
    titleLarge: TextStyle(
      fontFamily: anton,
      fontSize: 22,
      height: 1.15,
      color: text,
    ),
    titleMedium: TextStyle(
      fontFamily: anton,
      fontSize: 18,
      height: 1.2,
      color: text,
    ),
    titleSmall: TextStyle(
      fontFamily: archivo,
      fontSize: 16,
      fontWeight: FontWeight.w700,
      color: text,
    ),
    bodyLarge: TextStyle(fontFamily: archivo, fontSize: 16, color: text),
    bodyMedium: TextStyle(fontFamily: archivo, fontSize: 14, color: text),
    bodySmall: TextStyle(fontFamily: archivo, fontSize: 12, color: mutedText),
    labelLarge: TextStyle(
      fontFamily: archivo,
      fontSize: 14,
      fontWeight: FontWeight.w700,
      color: text,
    ),
    labelMedium: TextStyle(
      fontFamily: archivo,
      fontSize: 12,
      fontWeight: FontWeight.w700,
      color: text,
    ),
  );
}

OutlineInputBorder _inputBorder(Color color, {double width = 1}) {
  return OutlineInputBorder(
    borderRadius: BorderRadius.circular(_radius),
    borderSide: BorderSide(color: color, width: width),
  );
}

final class CourtBlazerAccentPanel extends StatelessWidget {
  const CourtBlazerAccentPanel({
    required this.child,
    this.padding,
    this.margin,
    super.key,
  });

  final Widget child;
  final EdgeInsetsGeometry? padding;
  final EdgeInsetsGeometry? margin;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final tokens = courtBlazerTokensOf(context);
    return Container(
      margin: margin,
      decoration: BoxDecoration(
        color: theme.colorScheme.surface,
        borderRadius: BorderRadius.circular(_radius),
        border: Border.all(color: tokens.border),
      ),
      clipBehavior: Clip.antiAlias,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(height: 2, color: tokens.accent),
          Padding(padding: padding ?? EdgeInsets.zero, child: child),
        ],
      ),
    );
  }
}

final class GameTimeLogo extends StatelessWidget {
  const GameTimeLogo({this.wordmark = true, this.height = 36, super.key});

  final bool wordmark;
  final double height;

  @override
  Widget build(BuildContext context) {
    final textStyle = Theme.of(context).textTheme.titleLarge!.copyWith(
      fontFamily: 'Anton',
      fontSize: height * 0.54,
    );
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        CustomPaint(
          size: Size(height * 1.22, height),
          painter: _GameTimePatchPainter(Theme.of(context)),
        ),
        if (wordmark) ...[
          const SizedBox(width: 10),
          Text('GameTime', style: textStyle),
        ],
      ],
    );
  }
}

final class _GameTimePatchPainter extends CustomPainter {
  const _GameTimePatchPainter(this.theme);

  final ThemeData theme;

  @override
  void paint(Canvas canvas, Size size) {
    final tokens =
        theme.extension<CourtBlazerTokens>() ??
        CourtBlazerTokens(
          accent: theme.colorScheme.secondary,
          border: theme.dividerColor,
          mutedText: theme.colorScheme.onSurfaceVariant,
          success: Colors.green,
        );
    final rect = Offset.zero & size;
    final radius = Radius.circular(size.height * 0.25);
    final shape = RRect.fromRectAndRadius(rect.deflate(1), radius);
    final background = Paint()..color = theme.colorScheme.surface;
    final border = Paint()
      ..color = theme.colorScheme.primary
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;

    canvas.drawRRect(shape, background);
    canvas.save();
    canvas.clipRRect(shape);
    final stripe = Path()
      ..moveTo(size.width * 0.08, size.height)
      ..lineTo(size.width * 0.34, size.height)
      ..lineTo(size.width * 0.92, 0)
      ..lineTo(size.width * 0.66, 0)
      ..close();
    canvas.drawPath(stripe, Paint()..color = tokens.accent);
    canvas.restore();
    canvas.drawRRect(shape, border);
    canvas.drawCircle(
      Offset(size.width * 0.22, size.height * 0.25),
      size.height * 0.055,
      Paint()..color = theme.colorScheme.primary,
    );

    final textPainter = TextPainter(
      text: TextSpan(
        text: 'GT',
        style: TextStyle(
          fontFamily: 'Anton',
          fontSize: size.height * 0.52,
          color: theme.colorScheme.onSurface,
          height: 1,
        ),
      ),
      textDirection: TextDirection.ltr,
    )..layout();
    textPainter.paint(
      canvas,
      Offset(
        (size.width - textPainter.width) / 2,
        (size.height - textPainter.height) / 2 + size.height * 0.03,
      ),
    );
  }

  @override
  bool shouldRepaint(covariant _GameTimePatchPainter oldDelegate) {
    return oldDelegate.theme != theme;
  }
}
