import 'dart:io';
import 'dart:ui' show ImageFilter, TileMode;

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

import '../state/app/modules/settings/bloc/settings_cubit.dart';
import '../storage/chat_background_settings.dart';
import '../theming/app_theme.dart';
import '../utils/app_paths.dart';

/// Renders the configurable chat background behind [child].
///
/// Layering (bottom → top): the background source (pattern / image / colour /
/// none), an optional black dim overlay, then [child]. The pattern source
/// keeps the legacy dark-mode colour inversion; user images never invert.
/// Reads [ChatBackgroundSettings] reactively, so the in-app live preview and
/// the real chat update together as the user drags the sliders.
class ChatBackground extends StatelessWidget {
  final Widget child;
  const ChatBackground({required this.child, super.key});

  static const _fallbackColor = Color(0xffefeae2);

  @override
  Widget build(BuildContext context) {
    final s = context.watch<SettingsCubit>().val().chatBackgroundSettings;
    final dark = AppTheme.isDarkMode(context);

    final Widget background;
    switch (s.type) {
      case ChatBackgroundType.none:
        background = ColoredBox(color: Theme.of(context).colorScheme.surface);
      case ChatBackgroundType.color:
        background = ColoredBox(color: Color(s.colorValue ?? _fallbackColor.toARGB32()));
      case ChatBackgroundType.pattern:
        background = _imageLayer(
          const AssetImage('assets/background/chat.png'),
          s,
          dark,
          isPattern: true,
        );
      case ChatBackgroundType.image:
        background = KeyedSubtree(
          // imageVersion changes on every replacement, forcing a fresh subtree
          // alongside the explicit ImageCache evict in the settings handler.
          key: ValueKey(s.imageVersion),
          child: _imageLayer(
            FileImage(File(AppPaths.chatBackgroundImage)),
            s,
            dark,
            isPattern: false,
          ),
        );
    }

    return Stack(
      fit: StackFit.expand,
      children: [
        Positioned.fill(child: background),
        if (s.dim > 0)
          Positioned.fill(
            child: ColoredBox(color: Colors.black.withValues(alpha: s.dim)),
          ),
        child,
      ],
    );
  }

  Widget _imageLayer(
    ImageProvider provider,
    ChatBackgroundSettings s,
    bool dark, {
    required bool isPattern,
  }) {
    final tiled = s.fit == ChatBackgroundFit.tile;
    final fit = switch (s.fit) {
      ChatBackgroundFit.cover => BoxFit.cover,
      ChatBackgroundFit.center => BoxFit.none,
      ChatBackgroundFit.tile => null,
    };

    Widget layer = DecoratedBox(
      decoration: BoxDecoration(
        image: DecorationImage(
          image: provider,
          fit: fit,
          alignment: Alignment.center,
          // The legacy pattern was rendered at scale 1.5 while tiling.
          scale: isPattern && tiled ? 1.5 : 1.0,
          repeat: tiled ? ImageRepeat.repeat : ImageRepeat.noRepeat,
          invertColors: isPattern && dark,
        ),
      ),
    );

    if (s.blur > 0) {
      layer = ImageFiltered(
        // mirror keeps cover-fit edges filled instead of bleeding to transparent.
        imageFilter: ImageFilter.blur(
          sigmaX: s.blur,
          sigmaY: s.blur,
          tileMode: TileMode.mirror,
        ),
        child: layer,
      );
    }
    return layer;
  }
}
