import 'dart:io';
import 'dart:typed_data';

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 '../../../storage/settings.dart' as model;
import '../../../utils/app_paths.dart';
import '../../../utils/haptics.dart';
import '../../../widget/async_action_button.dart';
import '../../../widget/chat_background.dart';
import '../../../widget/chat_background_picker_sheet.dart';
import '../../../widget/confirm_dialog.dart';
import 'data/default_settings.dart';

/// Predefined background colours offered for [ChatBackgroundType.color]. Keeps
/// us off a heavyweight colour-picker dependency while covering the common
/// messenger palette (neutrals + muted accents) that read well behind bubbles.
const List<Color> _colorPalette = [
  Color(0xffefeae2), // legacy beige
  Color(0xffffffff),
  Color(0xffe7ecef),
  Color(0xffd9e4dd),
  Color(0xffe4ddec),
  Color(0xfff3e2d4),
  Color(0xff2b3942), // dark teal
  Color(0xff1f1f1f),
  Color(0xff0b141a), // whatsapp dark
  Color(0xff3a2e2e),
];

/// Full-page editor for the global chat background, reached from the settings
/// list. Mirrors [ModulesSettingsPage]: a slim section tile navigates here, the
/// actual controls (source, fill, sliders) and a live preview live on this page.
class ChatBackgroundSettingsPage extends StatelessWidget {
  const ChatBackgroundSettingsPage({super.key});

  @override
  Widget build(BuildContext context) =>
      BlocBuilder<SettingsCubit, model.Settings>(
        builder: (context, _) {
          final settings = context.read<SettingsCubit>();
          final s = settings.val().chatBackgroundSettings;
          final isModified =
              s.toJson().toString() !=
              DefaultSettings.get().chatBackgroundSettings.toJson().toString();
          final showImageControls =
              s.type == ChatBackgroundType.pattern ||
              s.type == ChatBackgroundType.image;
          final showDim = s.type != ChatBackgroundType.none;

          return Scaffold(
            appBar: AppBar(
              title: const Text('Chat-Hintergrund'),
              actions: [
                IconButton(
                  tooltip: 'Auf Standard zurücksetzen',
                  icon: const Icon(Icons.undo_outlined),
                  onPressed: isModified
                      ? () => ConfirmDialog(
                          title: 'Hintergrund zurücksetzen?',
                          content:
                              'Quelle, Farbe und Darstellungsoptionen werden '
                              'auf das Standardmuster zurückgesetzt.',
                          confirmButton: 'Zurücksetzen',
                          onConfirm: () {
                            settings.val(write: true).chatBackgroundSettings =
                                DefaultSettings.get().chatBackgroundSettings;
                          },
                        ).asDialog(context)
                      : null,
                ),
              ],
            ),
            body: ListView(
              children: [
                Padding(
                  padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
                  child: _Preview(),
                ),
                ListTile(
                  leading: const Icon(Icons.wallpaper_outlined),
                  title: const Text('Quelle'),
                  trailing: DropdownButton<ChatBackgroundType>(
                    value: s.type,
                    icon: const Icon(Icons.arrow_drop_down),
                    items: _iconDropdownItems(
                      ChatBackgroundType.values,
                      _typeIcon,
                      _typeLabel,
                    ),
                    onChanged: (e) => _onTypeChanged(context, settings, e!),
                  ),
                ),
                if (s.type == ChatBackgroundType.image)
                  ListTile(
                    leading: const Icon(Icons.photo_library_outlined),
                    title: const Text('Bild ändern'),
                    onTap: () => _pickImage(context, settings),
                  ),
                if (s.type == ChatBackgroundType.image)
                  ListTile(
                    leading: const Icon(Icons.crop_outlined),
                    title: const Text('Zuschneiden'),
                    subtitle: const Text('Aktuelles Bild zuschneiden'),
                    onTap: () => _cropImage(context, settings),
                  ),
                if (s.type == ChatBackgroundType.color)
                  ListTile(
                    leading: const Icon(Icons.palette_outlined),
                    title: const Text('Farbe wählen'),
                    trailing: Container(
                      width: 28,
                      height: 28,
                      decoration: BoxDecoration(
                        color: Color(
                          s.colorValue ?? _colorPalette.first.toARGB32(),
                        ),
                        shape: BoxShape.circle,
                        border: Border.all(
                          color: Theme.of(context).dividerColor,
                        ),
                      ),
                    ),
                    onTap: () => _pickColor(context, settings),
                  ),
                if (showImageControls)
                  ListTile(
                    leading: const Icon(Icons.fit_screen_outlined),
                    title: const Text('Füllmodus'),
                    trailing: DropdownButton<ChatBackgroundFit>(
                      value: s.fit,
                      icon: const Icon(Icons.arrow_drop_down),
                      items: _iconDropdownItems(
                        ChatBackgroundFit.values,
                        _fitIcon,
                        _fitLabel,
                      ),
                      onChanged: (e) {
                        Haptics.selection();
                        settings.val(write: true).chatBackgroundSettings.fit =
                            e!;
                      },
                    ),
                  ),
                if (showDim)
                  _SliderTile(
                    icon: Icons.brightness_4_outlined,
                    label: 'Abdunkeln',
                    value: s.dim,
                    onChanged: (v) =>
                        settings.val(write: true).chatBackgroundSettings.dim = v,
                  ),
                if (showImageControls)
                  _SliderTile(
                    icon: Icons.blur_on_outlined,
                    label: 'Weichzeichnen',
                    value: s.blur,
                    min: 0,
                    max: 25,
                    onChanged: (v) => settings
                        .val(write: true)
                        .chatBackgroundSettings
                        .blur = v,
                  ),
              ],
            ),
          );
        },
      );

  Future<void> _onTypeChanged(
    BuildContext context,
    SettingsCubit settings,
    ChatBackgroundType type,
  ) async {
    // Selecting "image" without a stored file would render an empty/broken
    // FileImage — pick one first and only commit the type on success.
    if (type == ChatBackgroundType.image &&
        !File(AppPaths.chatBackgroundImage).existsSync()) {
      await _pickImage(context, settings);
      return;
    }
    Haptics.selection();
    settings.val(write: true).chatBackgroundSettings.type = type;
  }

  Future<void> _pickImage(BuildContext context, SettingsCubit settings) async {
    // Picks the image as-is — cropping is a separate, explicit step so the
    // user isn't forced through a cropper after every pick.
    final bytes = await showChatBackgroundPickerSheet(context);
    if (bytes == null || !context.mounted) return;
    await _storeImage(context, settings, bytes);
  }

  Future<void> _cropImage(BuildContext context, SettingsCubit settings) async {
    final file = File(AppPaths.chatBackgroundImage);
    if (!file.existsSync()) return;
    final current = await file.readAsBytes();
    if (!context.mounted) return;
    final cropped = await cropChatBackgroundImage(context, current);
    if (cropped == null || !context.mounted) return;
    await _storeImage(context, settings, cropped);
  }

  Future<void> _storeImage(
    BuildContext context,
    SettingsCubit settings,
    Uint8List bytes,
  ) async {
    await runWithErrorDialog(context, () async {
      final file = File(AppPaths.chatBackgroundImage);
      await file.writeAsBytes(bytes);
      // Same filename across replacements → the decoded image is cached under
      // an identical key. Evict so the new bytes actually show.
      await FileImage(file).evict();
      final cs = settings.val(write: true).chatBackgroundSettings;
      cs.imageVersion++;
      cs.type = ChatBackgroundType.image;
    });
  }

  Future<void> _pickColor(BuildContext context, SettingsCubit settings) async {
    final picked = await showModalBottomSheet<int>(
      context: context,
      showDragHandle: true,
      builder: (sheetContext) => SafeArea(
        child: Padding(
          padding: const EdgeInsets.fromLTRB(16, 0, 16, 24),
          child: Wrap(
            spacing: 16,
            runSpacing: 16,
            children: _colorPalette
                .map(
                  (c) => InkWell(
                    customBorder: const CircleBorder(),
                    onTap: () => Navigator.of(sheetContext).pop(c.toARGB32()),
                    child: Container(
                      width: 48,
                      height: 48,
                      decoration: BoxDecoration(
                        color: c,
                        shape: BoxShape.circle,
                        border: Border.all(
                          color: Theme.of(sheetContext).dividerColor,
                        ),
                      ),
                    ),
                  ),
                )
                .toList(),
          ),
        ),
      ),
    );
    if (picked == null) return;
    Haptics.selection();
    final cs = settings.val(write: true).chatBackgroundSettings;
    cs.colorValue = picked;
    cs.type = ChatBackgroundType.color;
  }

  /// Dropdown menu items rendered as an icon + label row, shared by the source
  /// and fill-mode pickers.
  static List<DropdownMenuItem<T>> _iconDropdownItems<T>(
    List<T> values,
    IconData Function(T) icon,
    String Function(T) label,
  ) => values
      .map(
        (e) => DropdownMenuItem<T>(
          value: e,
          child: Row(
            children: [
              Icon(icon(e)),
              const SizedBox(width: 10),
              Text(label(e)),
            ],
          ),
        ),
      )
      .toList();

  IconData _typeIcon(ChatBackgroundType type) => switch (type) {
    ChatBackgroundType.pattern => Icons.texture_outlined,
    ChatBackgroundType.image => Icons.image_outlined,
    ChatBackgroundType.color => Icons.format_color_fill_outlined,
    ChatBackgroundType.none => Icons.hide_image_outlined,
  };

  String _typeLabel(ChatBackgroundType type) => switch (type) {
    ChatBackgroundType.pattern => 'Standardmuster',
    ChatBackgroundType.image => 'Galerie-Bild',
    ChatBackgroundType.color => 'Einfarbig',
    ChatBackgroundType.none => 'Kein Hintergrund',
  };

  IconData _fitIcon(ChatBackgroundFit fit) => switch (fit) {
    ChatBackgroundFit.cover => Icons.crop_free_outlined,
    ChatBackgroundFit.tile => Icons.grid_on_outlined,
    ChatBackgroundFit.center => Icons.filter_center_focus_outlined,
  };

  String _fitLabel(ChatBackgroundFit fit) => switch (fit) {
    ChatBackgroundFit.cover => 'Füllen',
    ChatBackgroundFit.tile => 'Kacheln',
    ChatBackgroundFit.center => 'Zentrieren',
  };
}

/// Live preview that reuses the real [ChatBackground] renderer with a couple of
/// sample messages, so it stays in sync with the chat as settings change.
class _Preview extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final dark = Theme.of(context).brightness == Brightness.dark;
    // Approximate the real bubble colours from chat_bubble_styles.dart.
    final remoteColor = dark ? const Color(0xff202c33) : Colors.white;
    final selfColor = dark ? const Color(0xff005c4b) : const Color(0xffd3d3d3);

    return ClipRRect(
      borderRadius: BorderRadius.circular(12),
      child: SizedBox(
        height: 180,
        width: double.infinity,
        child: ChatBackground(
          child: Padding(
            padding: const EdgeInsets.all(12),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _bubble(
                  alignment: Alignment.centerLeft,
                  color: remoteColor,
                  text: 'Wie gefällt dir der neue Hintergrund?',
                  time: '09:41',
                ),
                const SizedBox(height: 8),
                _bubble(
                  alignment: Alignment.centerRight,
                  color: selfColor,
                  text: 'Sieht richtig gut aus! 🎉',
                  time: '09:42',
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget _bubble({
    required Alignment alignment,
    required Color color,
    required String text,
    required String time,
  }) {
    final onColor = ThemeData.estimateBrightnessForColor(color) == Brightness.dark
        ? Colors.white
        : Colors.black87;
    return Align(
      alignment: alignment,
      child: Container(
        constraints: const BoxConstraints(maxWidth: 220),
        padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
        decoration: BoxDecoration(
          color: color,
          borderRadius: BorderRadius.circular(12),
          boxShadow: const [
            BoxShadow(color: Colors.black26, blurRadius: 1, offset: Offset(0, 1)),
          ],
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.end,
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(text, style: TextStyle(color: onColor, fontSize: 13)),
            Text(
              time,
              style: TextStyle(
                color: onColor.withValues(alpha: 0.6),
                fontSize: 10,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _SliderTile extends StatelessWidget {
  final IconData icon;
  final String label;
  final double value;
  final double min;
  final double max;
  final ValueChanged<double> onChanged;

  const _SliderTile({
    required this.icon,
    required this.label,
    required this.value,
    required this.onChanged,
    this.min = 0,
    this.max = 1,
  });

  @override
  Widget build(BuildContext context) => ListTile(
    leading: Icon(icon),
    title: Text(label),
    subtitle: Slider(
      value: value.clamp(min, max),
      min: min,
      max: max,
      onChanged: onChanged,
      onChangeEnd: (_) => Haptics.selection(),
    ),
  );
}
