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

import 'package:hl_lieferservice/domain/entity/delivery.dart';
import 'package:hl_lieferservice/domain/entity/delivery_item.dart';
import 'package:hl_lieferservice/domain/entity/scan_progress.dart';
import 'package:hl_lieferservice/domain/entity/tour_details.dart';
import 'package:hl_lieferservice/feature/car_selection/bloc/bloc.dart';
import 'package:hl_lieferservice/feature/car_selection/bloc/state.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/detail/presentation/widget/discount_editor.dart';
import 'package:hl_lieferservice/feature/loading/widget/reason_catalog.dart';
import 'package:hl_lieferservice/feature/loading/widget/reason_picker_sheet.dart';

/// Step 3 — Artikel & Gutschriften.
///
/// * **Mengen-Gutschrift** (Belegzeile ganz ODER teilweise entfernen) ist
///   voll funktional über `RemoveItem`/`UnremoveItem` (mit `quantity`) →
///   Backend Audit-Action `remove`/`unremove`. Die `creditedQuantity` des
///   Items ist die Wahrheit (vom Server), kein lokaler Draft mehr.
///   Regeln (serverseitig erzwungen): scannbare Position muss `done` sein,
///   Lieferung muss `active` sein. Die UI spiegelt das als Gate + Hinweis.
/// * **Betrags-Gutschrift** (≤ 150 € in 10er-Schritten + Grund) ist
///   backend-gestützt über `SetDeliveryCredit`/`RemoveDeliveryCredit` am
///   `TourBloc` → `POST /deliveries/{id}/credit`. Wahrheit ist der Server
///   (`TourDetails.creditOf`), kein lokaler Draft mehr.
class StepArticles extends StatelessWidget {
  const StepArticles({
    super.key,
    required this.delivery,
    required this.details,
  });

  final Delivery delivery;
  final TourDetails details;

  @override
  Widget build(BuildContext context) {
    // Innerhalb einer Belegzeile: Oberartikel vor seinen Komponenten, damit
    // Komponenten direkt darunter eingerückt erscheinen.
    final items = List<DeliveryItem>.of(delivery.items)
      ..sort((a, b) {
        final byLine = a.belegzeilenNr.compareTo(b.belegzeilenNr);
        if (byLine != 0) return byLine;
        final byParent =
            (a.isComponent ? 1 : 0).compareTo(b.isComponent ? 1 : 0);
        if (byParent != 0) return byParent;
        return (a.komponentenArtikelNr ?? '')
            .compareTo(b.komponentenArtikelNr ?? '');
      });

    // Komponenten je Oberartikel (Artikelnummer des Parents → Komponenten).
    // Grundlage für E: Komponenten sind einzeln NICHT entfernbar — nur der
    // Oberartikel kann (ganzes Set) entfernt werden, was auf die Komponenten
    // kaskadiert.
    final componentsByParentNr = <String, List<DeliveryItem>>{};
    for (final it in items) {
      final pNr = it.parentArtikelNr;
      if (it.isComponent && pNr != null) {
        componentsByParentNr.putIfAbsent(pNr, () => []).add(it);
      }
    }
    List<DeliveryItem> componentsOf(DeliveryItem it) {
      final nr = details.articleOf(it.articleId)?.articleNumber;
      if (nr == null) return const [];
      return componentsByParentNr[nr] ?? const [];
    }

    return ListView(
      padding: const EdgeInsets.fromLTRB(16, 16, 16, 24),
      children: [
        _SectionHeader(text: 'Artikel'),
        const SizedBox(height: 8),
        if (delivery.state != DeliveryState.active) ...[
          const _LockedHint(
            text: 'Nur bei aktiver Lieferung änderbar.',
          ),
          const SizedBox(height: 8),
        ],
        if (items.isEmpty)
          const _EmptyHint(text: 'Keine Artikel hinterlegt.')
        else
          Card(
            margin: EdgeInsets.zero,
            child: Column(
              children: [
                for (int i = 0; i < items.length; i++) ...[
                  _ArticleManagementRow(
                    item: items[i],
                    details: details,
                    deliveryId: delivery.id,
                    deliveryActive: delivery.state == DeliveryState.active,
                    components: componentsOf(items[i]),
                  ),
                  if (i < items.length - 1)
                    const Divider(height: 1, indent: 16, endIndent: 16),
                ],
              ],
            ),
          ),
        const SizedBox(height: 24),
        _SectionHeader(text: 'Gutschriften'),
        const SizedBox(height: 8),
        Card(
          margin: EdgeInsets.zero,
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: DiscountEditor(
              deliveryId: delivery.id,
              active: delivery.state == DeliveryState.active,
            ),
          ),
        ),
      ],
    );
  }
}

class _SectionHeader extends StatelessWidget {
  const _SectionHeader({required this.text});
  final String text;

  @override
  Widget build(BuildContext context) {
    return Text(
      text,
      style: Theme.of(context).textTheme.titleMedium?.copyWith(
            fontWeight: FontWeight.w700,
          ),
    );
  }
}

class _EmptyHint extends StatelessWidget {
  const _EmptyHint({required this.text});
  final String text;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Card(
      margin: EdgeInsets.zero,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Text(
          text,
          style: TextStyle(
            color: theme.colorScheme.onSurfaceVariant,
            fontStyle: FontStyle.italic,
          ),
        ),
      ),
    );
  }
}

/// Eine Zeile in der Artikel-Verwaltung. Quelle der Wahrheit ist
/// `item.scanProgress.creditedQuantity` (vom Backend) — kein lokaler Draft.
/// Zeigt:
///   - verbleibende Liefermenge (Soll − Gutschrift)
///   - Gutschrift-Button → Mengen-Dialog (1…Restmenge + Grund), gesperrt für
///     scannbare, noch nicht gescannte Positionen oder inaktive Lieferung
///   - Wiederherstellen-Button, sobald etwas gutgeschrieben ist
class _ArticleManagementRow extends StatelessWidget {
  const _ArticleManagementRow({
    required this.item,
    required this.details,
    required this.deliveryId,
    required this.deliveryActive,
    this.components = const [],
  });

  final DeliveryItem item;
  final TourDetails details;
  final String deliveryId;
  final bool deliveryActive;

  /// Komponenten dieses Items, falls es ein Set-Oberartikel ist (sonst leer).
  /// Entfernen/Wiederherstellen kaskadiert auf diese Komponenten.
  final List<DeliveryItem> components;

  Future<void> _openCreditDialog(
    BuildContext context, {
    required int remaining,
  }) async {
    final tourBloc = context.read<TourBloc>();
    final actorCarId = _actorCarId(context);
    // Identische Auswahl wie im Beladen-/Scan-Screen: Grund-Picker
    // (Presets + „Anderer Grund") + Mengen-Stepper (Teilmengen-Gutschrift).
    final result = await showReasonPickerSheet(
      context: context,
      title: 'Grund für das Entfernen',
      presets: ReasonCatalog.itemRemove,
      confirmLabel: 'Entfernen',
      maxQuantity: remaining,
    );
    if (result == null) return;

    // Eine Aktion für ganz UND teilweise: das Backend kippt die Zeile auf
    // `removed`, sobald die volle Menge gutgeschrieben ist.
    tourBloc.add(RemoveItem(
      deliveryItemId: item.id,
      reason: result.reason,
      actorCarId: actorCarId,
      quantity: result.quantity,
      // Gutschrift-Grund zusätzlich als Lieferungs-Notiz festhalten.
      saveReasonAsNote: true,
    ));
  }

  void _restoreAll(BuildContext context) {
    // quantity: null → gesamte Gutschrift zurücknehmen.
    context.read<TourBloc>().add(UnremoveItem(
          deliveryItemId: item.id,
          actorCarId: _actorCarId(context),
        ));
  }

  /// Entfernt eine Anzahl Sets über den Oberartikel und kaskadiert auf seine
  /// Komponenten. Der Mengen-Stepper bleibt erhalten — ein Set kann mehrfach
  /// bestellt sein (Oberartikel-Menge = Set-Anzahl). Die Komponenten werden
  /// **proportional** mitreduziert (Stückzahl je Set × entfernte Sets),
  /// geklemmt auf die jeweilige Restmenge. Einzelne Komponenten bleiben
  /// nicht direkt entfernbar — nur dieser Weg über den Oberartikel.
  Future<void> _openSetRemoveDialog(
    BuildContext context, {
    required int remaining,
  }) async {
    final tourBloc = context.read<TourBloc>();
    final actorCarId = _actorCarId(context);
    final result = await showReasonPickerSheet(
      context: context,
      title: 'Grund für das Entfernen',
      presets: ReasonCatalog.itemRemove,
      confirmLabel: 'Entfernen',
      maxQuantity: remaining,
    );
    if (result == null) return;
    final n = result.quantity ?? remaining;
    final parentRequired = item.requiredQuantity;

    // Oberartikel um n Sets reduzieren.
    tourBloc.add(RemoveItem(
      deliveryItemId: item.id,
      reason: result.reason,
      actorCarId: actorCarId,
      quantity: n,
      saveReasonAsNote: true,
    ));
    // Komponenten proportional mitreduzieren.
    for (final c in components) {
      final cRemaining = c.requiredQuantity - c.scanProgress.creditedQuantity;
      if (cRemaining <= 0) continue;
      final proportional = parentRequired > 0
          ? (c.requiredQuantity * n / parentRequired).round()
          : cRemaining;
      final removeQty = proportional.clamp(0, cRemaining);
      if (removeQty <= 0) continue;
      tourBloc.add(RemoveItem(
        deliveryItemId: c.id,
        reason: result.reason,
        actorCarId: actorCarId,
        quantity: removeQty,
        // Grund nur einmal (am Oberartikel) als Notiz festhalten.
        saveReasonAsNote: false,
      ));
    }
  }

  /// Stellt das ganze Set wieder her (Oberartikel + Komponenten).
  void _restoreSet(BuildContext context) {
    final tourBloc = context.read<TourBloc>();
    final actorCarId = _actorCarId(context);
    tourBloc.add(UnremoveItem(deliveryItemId: item.id, actorCarId: actorCarId));
    for (final c in components) {
      tourBloc
          .add(UnremoveItem(deliveryItemId: c.id, actorCarId: actorCarId));
    }
  }

  /// Holt die aktuelle Auto-ID aus dem CarSelectBloc — gleiche Konvention
  /// wie der Loading-Flow: das aktiv gewählte Fahrzeug ist der „Akteur"
  /// des Audit-Events. Falls (defensiv) noch keine Auswahl getroffen ist,
  /// fallback auf einen Null-UUID-String, damit der Backend-Call nicht
  /// validation-failt.
  String _actorCarId(BuildContext context) {
    final state = context.read<CarSelectBloc>().state;
    if (state is CarSelectComplete) return state.selectedCar.id;
    return '00000000-0000-0000-0000-000000000000';
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final article = details.articleOf(item.articleId);
    final warehouse = details.warehouseOf(item.warehouseId);

    final required = item.requiredQuantity;
    final credited = item.scanProgress.creditedQuantity;
    final remaining = required - credited;
    final fullyRemoved = item.isRemoved; // Status == removed (voll gutgeschr.)
    final partiallyCredited = credited > 0 && !fullyRemoved;

    // E: Komponenten eines Sets sind einzeln NICHT entfernbar; nur der
    // Oberartikel kann (ganzes Set) entfernt werden.
    final isComponent = item.isComponent;
    final hasComponents = components.isNotEmpty;

    // Gate: scannbare Position muss `done` sein, sonst keine Gutschrift.
    final scannable = article?.scannable ?? false;
    final isDone = item.scanProgress.status == ScanStatus.done;
    final blockedByScan = scannable && !isDone && !fullyRemoved;
    // Beim Set zusätzlich: jede scanbare Komponente muss erst verladen sein,
    // sonst würde das Backend deren Entfernen ablehnen.
    final componentsBlocked = components.any((c) {
      final cArticle = details.articleOf(c.articleId);
      final cScannable = cArticle?.scannable ?? false;
      final cDone = c.scanProgress.status == ScanStatus.done;
      return cScannable && !cDone && !c.isRemoved;
    });
    final canCredit = deliveryActive &&
        !blockedByScan &&
        !componentsBlocked &&
        remaining > 0;

    final Color avatarColor;
    final String avatarText;
    if (fullyRemoved) {
      avatarColor = Colors.red.shade400;
      avatarText = '0×';
    } else if (partiallyCredited) {
      avatarColor = Colors.amber.shade700;
      avatarText = '$remaining×';
    } else {
      avatarColor = theme.colorScheme.primary;
      avatarText = '$required×';
    }

    return ListTile(
      // Komponenten um eine Stufe eingerückt (gehören zum Oberartikel darüber).
      contentPadding:
          EdgeInsets.only(left: item.isComponent ? 40 : 16, right: 16),
      leading: CircleAvatar(
        backgroundColor: avatarColor,
        foregroundColor: theme.colorScheme.onPrimary,
        child: Text(
          avatarText,
          style: const TextStyle(fontSize: 11, fontWeight: FontWeight.bold),
        ),
      ),
      title: Text(
        '${item.isComponent ? '↳ ' : ''}${article?.name ?? '⟨Unbekannter Artikel⟩'}',
        style: TextStyle(
          fontWeight: FontWeight.w600,
          decoration: fullyRemoved ? TextDecoration.lineThrough : null,
          color: fullyRemoved ? theme.colorScheme.onSurfaceVariant : null,
        ),
      ),
      subtitle: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            [
              article?.articleNumber ?? item.articleId,
              if (warehouse != null) warehouse.name,
              if (article?.scannable == false) 'Dienstleistung',
            ].join(' · '),
            style: TextStyle(
              fontSize: 12,
              color: theme.colorScheme.onSurfaceVariant,
            ),
          ),
          if (fullyRemoved)
            _StatusLine(
              text: 'Komplett gutgeschrieben'
                  '${item.scanProgress.heldReason != null ? ' – ${item.scanProgress.heldReason}' : ''}',
              color: Colors.red.shade400,
            )
          else if (partiallyCredited)
            _StatusLine(
              text: '$credited von $required gutgeschrieben',
              color: Colors.amber.shade800,
            ),
          if (blockedByScan)
            _StatusLine(
              text: 'Erst scannen/verladen — dann Gutschrift möglich',
              color: theme.colorScheme.onSurfaceVariant,
            ),
          // E: Komponenten-Hinweis — einzeln nicht entfernbar.
          if (isComponent && deliveryActive && !fullyRemoved)
            _StatusLine(
              text: 'Nur über den Oberartikel entfernbar',
              color: theme.colorScheme.onSurfaceVariant,
            ),
          // Set-Oberartikel: blockiert, solange eine Komponente noch nicht
          // verladen ist.
          if (hasComponents &&
              componentsBlocked &&
              deliveryActive &&
              !fullyRemoved)
            _StatusLine(
              text: 'Erst alle Set-Teile verladen — dann ganzes Set entfernbar',
              color: theme.colorScheme.onSurfaceVariant,
            ),
        ],
      ),
      // E: Komponenten haben KEINE eigenen Aktionen — Entfernen/Wiederherstellen
      // läuft ausschließlich über den Oberartikel (kaskadiert auf das Set).
      trailing: isComponent
          ? null
          : Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                if (credited > 0)
                  IconButton(
                    // Wiederherstellen nur bei aktiver Lieferung — bei
                    // abgeschlossener/abgebrochener Lieferung gesperrt (greift
                    // auch backend-seitig, hier zusätzlich in der UI).
                    tooltip: deliveryActive
                        ? (hasComponents
                            ? 'Set wiederherstellen'
                            : 'Gutschrift zurücknehmen')
                        : 'Nur bei aktiver Lieferung',
                    icon: Icon(
                      Icons.restore,
                      color: deliveryActive
                          ? theme.colorScheme.primary
                          : theme.colorScheme.onSurfaceVariant,
                    ),
                    onPressed: deliveryActive
                        ? () => hasComponents
                            ? _restoreSet(context)
                            : _restoreAll(context)
                        : null,
                  ),
                if (!fullyRemoved)
                  IconButton.outlined(
                    tooltip: (blockedByScan || componentsBlocked)
                        ? 'Erst scannen/verladen'
                        : (!deliveryActive
                            ? 'Nur bei aktiver Lieferung'
                            : (hasComponents
                                ? 'Ganzes Set entfernen'
                                : 'Gutschrift / entfernen')),
                    style: ButtonStyle(
                      backgroundColor: WidgetStatePropertyAll(
                        canCredit
                            ? Colors.redAccent
                            : theme.colorScheme.surfaceContainerHighest,
                      ),
                    ),
                    onPressed: canCredit
                        ? () => hasComponents
                            ? _openSetRemoveDialog(context, remaining: remaining)
                            : _openCreditDialog(context, remaining: remaining)
                        : null,
                    icon: Icon(
                      Icons.delete,
                      color: canCredit
                          ? theme.colorScheme.onPrimary
                          : theme.colorScheme.onSurfaceVariant,
                    ),
                  ),
              ],
            ),
    );
  }
}

/// Kleine farbige Statuszeile unter dem Artikelnamen.
class _StatusLine extends StatelessWidget {
  const _StatusLine({required this.text, required this.color});
  final String text;
  final Color color;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 2),
      child: Text(
        text,
        style: TextStyle(
          fontSize: 11,
          fontWeight: FontWeight.w600,
          color: color,
        ),
      ),
    );
  }
}

/// Lock-Hinweis (analog DiscountEditor): zeigt mit Schloss-Symbol an, dass die
/// Artikel-Aktionen (Entfernen / Wiederherstellen) nur bei aktiver Lieferung
/// möglich sind.
class _LockedHint extends StatelessWidget {
  const _LockedHint({required this.text});
  final String text;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: theme.colorScheme.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(8),
      ),
      child: Row(
        children: [
          Icon(Icons.lock_outline,
              size: 16, color: theme.colorScheme.onSurfaceVariant),
          const SizedBox(width: 8),
          Expanded(
            child: Text(
              text,
              style: theme.textTheme.bodySmall?.copyWith(
                color: theme.colorScheme.onSurfaceVariant,
              ),
            ),
          ),
        ],
      ),
    );
  }
}
