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

import '../../../../state/app/modules/timetable/bloc/timetable_bloc.dart';
import '../../../../widget/app_progress_indicator.dart';
import '../../../../widget/async_action_button.dart';
import '../../../../widget/details_bottom_sheet.dart';
import '../data/subject_color_palette.dart';

typedef ColorPickCallback = Future<void> Function(SubjectColor option);

/// Gemeinsames Farbauswahl-Sheet für Fächer und eigene Termine. Beim Antippen
/// einer Farbe läuft [onSelected] (bzw. [onReset] für die Standardfarbe);
/// solange zeigt der gewählte Kreis einen Spinner und blockiert weitere
/// Eingaben. Bei Erfolg schließt das Sheet, bei Fehler bleibt es offen und
/// zeigt die Meldung inline — konsistent mit [AsyncListTile]/[AsyncDialogAction].
/// Der Aufrufer entscheidet, ob der Wert lokal übernommen oder direkt
/// persistiert wird.
Future<void> showTimetableColorPicker(
  BuildContext context, {
  required String title,
  String? subtitle,
  SubjectColor? current,
  required ColorPickCallback onSelected,
  Future<void> Function()? onReset,
}) {
  return showDetailsBottomSheet(
    context,
    header: ListTile(
      leading: const Icon(Icons.palette_outlined, size: 32),
      title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
      subtitle: subtitle == null ? null : Text(subtitle),
    ),
    children: (sheetCtx) => [
      _ColorChoices(
        current: current,
        onSelected: onSelected,
        onReset: onReset,
        sheetContext: sheetCtx,
      ),
    ],
  );
}

/// Fach-spezifischer Wrapper: öffnet den Picker und persistiert die Auswahl
/// direkt über den [TimetableBloc].
Future<void> showSubjectColorPicker(
  BuildContext context, {
  required String subjectShort,
  required String subjectLabel,
  String? currentColorName,
}) {
  final bloc = context.read<TimetableBloc>();
  return showTimetableColorPicker(
    context,
    title: 'Farbe: $subjectLabel',
    subtitle: 'Nur reguläre Stunden werden eingefärbt',
    current: SubjectColorPalette.fromName(currentColorName),
    onSelected: (option) => bloc.setSubjectColor(subjectShort, option.name),
    onReset: () => bloc.clearSubjectColor(subjectShort),
  );
}

class _ColorChoices extends StatefulWidget {
  final SubjectColor? current;
  final ColorPickCallback onSelected;
  final Future<void> Function()? onReset;
  final BuildContext sheetContext;

  const _ColorChoices({
    required this.current,
    required this.onSelected,
    required this.onReset,
    required this.sheetContext,
  });

  @override
  State<_ColorChoices> createState() => _ColorChoicesState();
}

class _ColorChoicesState extends State<_ColorChoices> {
  final AsyncActionController _controller = AsyncActionController();
  SubjectColor? _pendingColor;
  bool _pendingReset = false;

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  Future<void> _run(
    Future<void> Function() action, {
    SubjectColor? color,
    bool reset = false,
  }) async {
    if (_controller.busy) return;
    setState(() {
      _pendingColor = color;
      _pendingReset = reset;
    });
    final ok = await _controller.run(action);
    if (!mounted) return;
    setState(() {
      _pendingColor = null;
      _pendingReset = false;
    });
    if (ok && widget.sheetContext.mounted) {
      Navigator.of(widget.sheetContext).pop();
    }
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, _) {
        final busy = _controller.busy;
        final err = _controller.error;
        return Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Padding(
              padding: const EdgeInsets.all(16),
              child: Wrap(
                spacing: 14,
                runSpacing: 14,
                children: [
                  for (final option in SubjectColor.values)
                    _ColorDot(
                      display: SubjectColorPalette.displayOf(option),
                      selected: option == widget.current,
                      loading: _pendingColor == option,
                      onTap: busy
                          ? null
                          : () => _run(
                              () => widget.onSelected(option),
                              color: option,
                            ),
                    ),
                ],
              ),
            ),
            if (widget.onReset != null) ...[
              const Divider(height: 1),
              ListTile(
                leading: _pendingReset
                    ? const SizedBox(
                        width: 24,
                        height: 24,
                        child: AppProgressIndicator.small(),
                      )
                    : const Icon(Icons.format_color_reset_outlined),
                title: const Text('Standardfarbe'),
                subtitle: const Text('Farbe entfernen'),
                enabled: widget.current != null && !busy,
                onTap: () => _run(widget.onReset!, reset: true),
              ),
            ],
            if (err != null)
              Padding(
                padding: const EdgeInsets.only(left: 16, right: 16, bottom: 8),
                child: Text(
                  err,
                  style: TextStyle(
                    color: Theme.of(context).colorScheme.error,
                    fontSize: 13,
                  ),
                ),
              ),
          ],
        );
      },
    );
  }
}

/// Kompakter Header-Button (Palettensymbol mit rundem Farb-Badge) für die
/// Detail-Sheets. Öffnet den gemeinsamen [showTimetableColorPicker]; das Badge
/// zeigt die aktuelle Farbe (bzw. nichts) und wird erst nach erfolgreichem
/// Speichern aktualisiert. [onSelected]/[onReset] persistieren und werfen bei
/// Fehler (die Meldung erscheint dann inline im Picker-Sheet).
class TimetableColorHeaderButton extends StatefulWidget {
  final String? initialColorName;
  final String pickerTitle;
  final String? pickerSubtitle;
  final Future<void> Function(SubjectColor option) onSelected;
  final Future<void> Function()? onReset;

  const TimetableColorHeaderButton({
    required this.initialColorName,
    required this.pickerTitle,
    required this.onSelected,
    this.pickerSubtitle,
    this.onReset,
    super.key,
  });

  @override
  State<TimetableColorHeaderButton> createState() =>
      _TimetableColorHeaderButtonState();
}

class _TimetableColorHeaderButtonState
    extends State<TimetableColorHeaderButton> {
  late SubjectColor? _current = SubjectColorPalette.fromName(
    widget.initialColorName,
  );

  Future<void> _pick() {
    return showTimetableColorPicker(
      context,
      title: widget.pickerTitle,
      subtitle: widget.pickerSubtitle,
      current: _current,
      onSelected: (option) async {
        await widget.onSelected(option);
        if (mounted) setState(() => _current = option);
      },
      onReset: widget.onReset == null
          ? null
          : () async {
              await widget.onReset!();
              if (mounted) setState(() => _current = null);
            },
    );
  }

  @override
  Widget build(BuildContext context) {
    final color = _current == null
        ? null
        : SubjectColorPalette.displayOf(_current!).color;
    return IconButton(
      tooltip: 'Farbe',
      onPressed: _pick,
      icon: Stack(
        clipBehavior: Clip.none,
        children: [
          const Icon(Icons.palette_outlined),
          if (color != null)
            // Größe und Position wie ein Label-Badge (Material largeSize),
            // nur leer und rund.
            Positioned(
              top: -6,
              right: -6,
              child: Container(
                width: 16,
                height: 16,
                decoration: BoxDecoration(shape: BoxShape.circle, color: color),
              ),
            ),
        ],
      ),
    );
  }
}

class _ColorDot extends StatelessWidget {
  final ColorModeDisplay display;
  final bool selected;
  final bool loading;
  final VoidCallback? onTap;

  const _ColorDot({
    required this.display,
    required this.selected,
    required this.loading,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Tooltip(
      message: display.displayName,
      child: InkWell(
        onTap: onTap,
        customBorder: const CircleBorder(),
        child: Container(
          width: 48,
          height: 48,
          alignment: Alignment.center,
          decoration: BoxDecoration(
            color: display.color,
            shape: BoxShape.circle,
            border: selected
                ? Border.all(
                    color: Theme.of(context).colorScheme.onSurface,
                    width: 3,
                  )
                : null,
          ),
          child: loading
              ? const AppProgressIndicator.small(color: Colors.white)
              : (selected
                    ? const Icon(Icons.check, color: Colors.white)
                    : null),
        ),
      ),
    );
  }
}
