import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/bloc/phase_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/bloc/phase_event.dart';
import 'package:hl_lieferservice/feature/delivery/bloc/tour_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/bloc/tour_event.dart';
import 'package:hl_lieferservice/feature/delivery/bloc/tour_state.dart';
import 'package:hl_lieferservice/feature/delivery/model/delivery_phase.dart';
import 'package:hl_lieferservice/feature/delivery/overview/widget/sortable_delivery_list.dart';
import 'package:hl_lieferservice/widget/home/presentation/home_drawer.dart';
import 'package:hl_lieferservice/widget/phase_stepper/phase_stepper.dart';

/// Page für die zweite Phase des Lieferprozesses (Sortieren). Der Fahrer
/// legt per Drag&Drop die Reihenfolge fest, ändert lokal so oft er möchte
/// und bestätigt am Ende mit einem expliziten Klick. Erst dann wird die
/// Reihenfolge ans Backend übertragen und in Phase [DeliveryPhase.beladen]
/// gewechselt.
class DeliverySortPage extends StatefulWidget {
  const DeliverySortPage({
    super.key,
    required this.selectedCarId,
    this.onPhaseAdvanced,
  });

  final int selectedCarId;

  /// Optionaler Hook, damit die übergeordnete Routing-Stelle nach Erfolg
  /// auf die nächste Phase wechseln kann (rerender der Beladungs-Page).
  final VoidCallback? onPhaseAdvanced;

  @override
  State<StatefulWidget> createState() => _DeliverySortPageState();
}

class _DeliverySortPageState extends State<DeliverySortPage> {
  late final SortableDeliveryListController _listController;

  /// Verhindert mehrfache SnackBars für denselben Fehler-State.
  String? _lastShownErrorSignature;

  /// Letzter Tour-"Fingerabdruck" (Anzahl + erste/letzte ID), zu dem wir den
  /// Sortier-Bucket des aktuellen Autos bereits konsistent gemacht haben.
  /// Verhindert unnötige Event-Stürme, wenn der TourBloc häufig rebuildet.
  String? _lastEnsuredTourSignature;

  /// Trackt, ob im letzten Listener-Tick `isPersistingSorting` true war —
  /// damit wir den Übergang persisting → fertig zuverlässig erkennen,
  /// auch wenn der Listener für Bucket-Maintenance bereits zwischendurch
  /// gefeuert hat.
  bool _wasPersisting = false;

  @override
  void initState() {
    super.initState();
    _listController = SortableDeliveryListController();
    // Falls Tour bereits geladen ist: Sortier-Bucket sofort konsistent
    // machen. Sonst übernimmt das der BlocConsumer-Listener beim ersten
    // TourLoaded.
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) return;
      _ensureBucketIfNeeded(context.read<TourBloc>().state);
    });
  }

  String _tourSignature(TourLoaded state) {
    final ids = state.tour.deliveries.map((d) => d.id).toList();
    if (ids.isEmpty) return "0";
    return "${ids.length}|${ids.first}|${ids.last}";
  }

  void _ensureBucketIfNeeded(TourState state) {
    if (state is! TourLoaded) return;
    final signature = _tourSignature(state);
    if (signature == _lastEnsuredTourSignature) return;
    _lastEnsuredTourSignature = signature;
    context.read<TourBloc>().add(
      EnsureSortingForCarEvent(carId: widget.selectedCarId.toString()),
    );
  }

  List<String> _orderedIdsFor(TourLoaded state) {
    return state.sortingInformation[widget.selectedCarId.toString()] ??
        const <String>[];
  }

  /// Phase im zentralen [PhaseBloc] auf "beladen" setzen. Der Bloc kümmert
  /// sich um Persistenz via [PhaseService]. Der optionale UI-Callback wird
  /// (aus Rückwärtskompatibilität) zusätzlich gefeuert.
  void _advanceToLoading() {
    context.read<PhaseBloc>().add(
          PhaseSet(
            carId: widget.selectedCarId.toString(),
            phase: DeliveryPhase.beladen,
          ),
        );
    widget.onPhaseAdvanced?.call();
  }

  void _skipEmptyToLoading() => _advanceToLoading();

  void _confirm() {
    // _wasPersisting hier setzen — der erste Listener-Tick mit
    // isPersistingSorting=true wird von listenWhen herausgefiltert
    // (kein "phaseEnded"-Übergang), daher müssen wir das Flag vorher
    // selbst hochziehen. Sonst erkennt der Listener beim zweiten Tick
    // (isPersistingSorting=false) den Übergang nicht und der
    // Phasen-Wechsel auf "beladen" bleibt aus.
    _wasPersisting = true;
    context.read<TourBloc>().add(
      ConfirmSortingEvent(carId: widget.selectedCarId.toString()),
    );
  }

  Widget _hintCard({required IconData icon, required String text, Color? color}) {
    return Padding(
      padding: const EdgeInsets.all(15),
      child: Row(
        children: [
          Padding(
            padding: const EdgeInsets.only(right: 15),
            child: Icon(icon, color: color ?? Colors.blueAccent),
          ),
          Expanded(child: Text(text)),
        ],
      ),
    );
  }

  Widget _emptyState() {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        const Icon(Icons.inbox_outlined, size: 64, color: Colors.grey),
        const SizedBox(height: 12),
        Text(
          "Keine Lieferungen heute",
          style: Theme.of(context).textTheme.titleMedium,
        ),
        const SizedBox(height: 6),
        const Padding(
          padding: EdgeInsets.symmetric(horizontal: 32),
          child: Text(
            "Für das ausgewählte Fahrzeug sind heute keine Lieferungen geplant.",
            textAlign: TextAlign.center,
          ),
        ),
      ],
    );
  }

  Widget _singleDeliveryHint(String singleId, TourLoaded state) {
    final delivery = state.tour.deliveries.firstWhere(
      (d) => d.id == singleId,
      orElse: () => state.tour.deliveries.first,
    );
    return Column(
      children: [
        _hintCard(
          icon: Icons.info_outline,
          text:
              "Nur eine Lieferung — die Reihenfolge ist trivial. "
              "Tippen Sie auf \"Weiter zur Beladung\", um fortzufahren.",
        ),
        const Divider(),
        ListTile(
          leading: CircleAvatar(
            backgroundColor: Theme.of(context).primaryColor,
            child: Text(
              "1",
              style: TextStyle(
                color: Theme.of(context).colorScheme.onSecondary,
              ),
            ),
          ),
          title: Text(delivery.customer.name),
          subtitle: Text(
            delivery.customer.address.toString(),
            style: const TextStyle(fontSize: 11),
          ),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return BlocConsumer<TourBloc, TourState>(
      listenWhen: (prev, curr) {
        // Bucket-Maintenance: erstes TourLoaded oder Tour-Inhalt geändert.
        final bucketTrigger = (prev is! TourLoaded && curr is TourLoaded) ||
            (prev is TourLoaded &&
                curr is TourLoaded &&
                prev.tour.deliveries.length != curr.tour.deliveries.length);
        if (bucketTrigger) return true;

        if (prev is! TourLoaded || curr is! TourLoaded) return false;
        final phaseEnded =
            prev.isPersistingSorting && !curr.isPersistingSorting;
        final newError =
            curr.sortingPersistError != null &&
            curr.sortingPersistError != prev.sortingPersistError;
        return phaseEnded || newError;
      },
      listener: (context, state) {
        if (state is! TourLoaded) return;

        // 1) Bucket-Konsistenz nachziehen, falls die Tour gerade erst geladen
        //    wurde oder sich verändert hat.
        _ensureBucketIfNeeded(state);

        // 2) Fehler-SnackBar für Confirm-Fehler.
        final err = state.sortingPersistError;
        if (err != null && err != _lastShownErrorSignature) {
          _lastShownErrorSignature = err;
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text(err)),
          );
          _wasPersisting = state.isPersistingSorting;
          return;
        }

        // 3) Echter Übergang persisting → fertig + kein Fehler → erfolgreich
        //    bestätigt → nächste Phase. Übergang über das Feld _wasPersisting
        //    erkannt, da der Listener auch bei Bucket-Triggern feuert.
        if (_wasPersisting && !state.isPersistingSorting && err == null) {
          _advanceToLoading();
        }
        _wasPersisting = state.isPersistingSorting;
      },
      builder: (context, state) {
        if (state is! TourLoaded) {
          return const Scaffold(
            body: Center(child: CircularProgressIndicator()),
          );
        }

        final orderedIds = _orderedIdsFor(state);

        return Scaffold(
          drawer: const HomeAppDrawer(),
          appBar: PreferredSize(
            preferredSize: const Size.fromHeight(140),
            child: PhaseStepper(
              currentPhase: DeliveryPhase.sortieren,
              carId: widget.selectedCarId.toString(),
            ),
          ),
          body: SafeArea(
            child: _buildBody(state, orderedIds),
          ),
          bottomNavigationBar: _buildBottomBar(state, orderedIds),
        );
      },
    );
  }

  Widget _buildBody(TourLoaded state, List<String> orderedIds) {
    if (orderedIds.isEmpty) {
      return _emptyState();
    }

    if (orderedIds.length == 1) {
      return _singleDeliveryHint(orderedIds.first, state);
    }

    return Column(
      children: [
        _hintCard(
          icon: Icons.info_outline,
          text:
              "Ziehen Sie die einzelnen Lieferungen mit dem Finger in die "
              "gewünschte Position. Die Reihenfolge wird erst beim "
              "Bestätigen ans System übertragen.",
        ),
        const Divider(height: 1),
        Expanded(
          child: SortableDeliveryList(
            selectedCarId: widget.selectedCarId,
            controller: _listController,
          ),
        ),
      ],
    );
  }

  Widget _buildBottomBar(TourLoaded state, List<String> orderedIds) {
    final isLoading = state.isPersistingSorting;
    final theme = Theme.of(context);

    // Spezialfälle: 0 / 1 Lieferungen → vereinfachte BottomBar
    if (orderedIds.isEmpty) {
      return SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(12),
          child: SizedBox(
            width: double.infinity,
            child: FilledButton.icon(
              onPressed: isLoading ? null : _skipEmptyToLoading,
              icon: const Icon(Icons.arrow_forward),
              label: const Text("Weiter zur Beladung"),
            ),
          ),
        ),
      );
    }

    if (orderedIds.length == 1) {
      return SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(12),
          child: SizedBox(
            width: double.infinity,
            child: FilledButton.icon(
              onPressed: isLoading ? null : _confirm,
              icon: isLoading
                  ? const SizedBox(
                      width: 16,
                      height: 16,
                      child: CircularProgressIndicator(
                        strokeWidth: 2,
                        color: Colors.white,
                      ),
                    )
                  : const Icon(Icons.arrow_forward),
              label: const Text("Weiter zur Beladung"),
            ),
          ),
        ),
      );
    }

    return SafeArea(
      child: Padding(
        padding: const EdgeInsets.all(12),
        child: Row(
          children: [
            Expanded(
              child: OutlinedButton.icon(
                onPressed: isLoading
                    ? null
                    : () => _listController.resetToDefault(),
                icon: const Icon(Icons.restart_alt),
                label: const Text("Zurücksetzen"),
              ),
            ),
            const SizedBox(width: 12),
            Expanded(
              flex: 2,
              child: FilledButton.icon(
                onPressed: isLoading ? null : _confirm,
                icon: isLoading
                    ? SizedBox(
                        width: 16,
                        height: 16,
                        child: CircularProgressIndicator(
                          strokeWidth: 2,
                          color: theme.colorScheme.onPrimary,
                        ),
                      )
                    : const Icon(Icons.check),
                label: const Text("Reihenfolge bestätigen"),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
