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

import 'package:hl_lieferservice/domain/entity/contact_source.dart';
import 'package:hl_lieferservice/domain/entity/customer.dart';
import 'package:hl_lieferservice/domain/entity/delivery.dart';
import 'package:hl_lieferservice/domain/entity/delivery_item.dart';
import 'package:hl_lieferservice/domain/entity/tour_details.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/bloc/workflow_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/detail/bloc/workflow_event.dart';
import 'package:hl_lieferservice/feature/delivery/detail/bloc/workflow_state.dart';

/// Step 1 — Informationen zur Lieferung.
///
/// Schnellaktionen oben (Anrufen, Maps, Status-Menü), darunter
/// Sondervereinbarungen + Wunschzeit, Kunden-Block (Name + Adresse +
/// Kontakte), zu liefernde Artikel inkl. nicht-scanbarer
/// Dienstleistungen (z. B. „Aufbauservice", „Anlieferung"). Reine
/// Anzeige — Schreib-Aktionen wandern in die anderen Steps.
class StepInfo extends StatelessWidget {
  const StepInfo({super.key, required this.delivery, required this.details});

  final Delivery delivery;
  final TourDetails details;

  @override
  Widget build(BuildContext context) {
    final customer = details.customerOf(delivery);
    final contacts = details.contactsOf(delivery).toList();
    // Vereint Quellen mit identischem Namen + identischer Channel-Liste,
    // damit derselbe Datensatz nicht zweimal (z. B. „Belegadresse" UND
    // „Kundenstamm") aufpoppt.
    final mergedSources = details.mergedContactSourcesOf(delivery);

    return ListView(
      padding: const EdgeInsets.fromLTRB(16, 16, 16, 16),
      children: [
        _SectionHeader(text: 'Beleg'),
        const SizedBox(height: 8),
        _BelegCard(delivery: delivery),
        const SizedBox(height: 24),
        _SectionHeader(text: 'Schnellaktionen'),
        const SizedBox(height: 8),
        _QuickActions(
          delivery: delivery,
          customer: customer,
          mergedSources: mergedSources,
        ),
        const SizedBox(height: 24),
        _SectionHeader(text: 'Sondervereinbarungen'),
        const SizedBox(height: 8),
        _AgreementsCard(delivery: delivery),
        const SizedBox(height: 24),
        _SectionHeader(text: 'Kundeninformationen'),
        const SizedBox(height: 8),
        _CustomerCard(customer: customer, contacts: contacts),
        if (mergedSources.isNotEmpty) ...[
          const SizedBox(height: 24),
          _SectionHeader(text: 'Alle Kontaktinfos'),
          const SizedBox(height: 8),
          _AllContactsCard(sources: mergedSources),
        ],
        const SizedBox(height: 24),
        _SectionHeader(text: 'Zu liefernde Artikel'),
        const SizedBox(height: 8),
        _ArticleList(delivery: delivery, details: details),
      ],
    );
  }
}

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

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

// ─── Beleg ──────────────────────────────────────────────────────────────

class _BelegCard extends StatelessWidget {
  const _BelegCard({required this.delivery});

  final Delivery delivery;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Card(
      margin: EdgeInsets.zero,
      child: ListTile(
        leading: Icon(
          Icons.receipt_long_outlined,
          color: theme.colorScheme.primary,
        ),
        title: const Text('Belegnummer'),
        subtitle: Text(
          delivery.erpBelegnummer,
          style: theme.textTheme.titleMedium?.copyWith(
            fontWeight: FontWeight.w700,
          ),
        ),
      ),
    );
  }
}

// ─── Schnellaktionen ────────────────────────────────────────────────────

enum _StatusAction { hold, cancel, resume }

class _QuickActions extends StatelessWidget {
  const _QuickActions({
    required this.delivery,
    required this.customer,
    required this.mergedSources,
  });

  final Delivery delivery;
  final Customer? customer;
  final List<MergedContactSource> mergedSources;

  /// Alle aus den Beleg-Kontaktquellen anrufbaren Nummern, in
  /// Sheet-Anzeigeform aufbereitet:
  ///
  /// * Phone vor Mobile pro Quelle, Quelle-Reihenfolge wie vom Backend.
  /// * Duplikate gleicher Nummer (z. B. dieselbe Mobilnummer in Beleg-
  ///   und Kunden­stammadresse) werden auf den ersten Eintrag gemerged,
  ///   die zweite Rolle ergänzt das Label.
  /// * Whitespace wird zum Vergleich entfernt, damit „+49 89 123" und
  ///   „+498 9123" als dieselbe Nummer durchgehen, falls der Anwender
  ///   sie mal mit, mal ohne Leerzeichen erfasst hat. Angezeigt wird der
  ///   Originalwert der ersten Quelle.
  List<_CallableNumber> _collectCallableNumbers() {
    final out = <_CallableNumber>[];
    final byNormalized = <String, int>{};
    for (final src in mergedSources) {
      for (final ch in src.channels) {
        if (ch.kind != ContactKind.phone && ch.kind != ContactKind.mobile) {
          continue;
        }
        final normalized = ch.value.replaceAll(RegExp(r'\s+'), '');
        if (normalized.isEmpty) continue;
        final existing = byNormalized[normalized];
        if (existing != null) {
          out[existing] = out[existing].withAdditionalRole(src.rolesLabel);
          continue;
        }
        byNormalized[normalized] = out.length;
        out.add(_CallableNumber(
          value: ch.value,
          kind: ch.kind,
          roleLabel: src.rolesLabel,
          displayName: src.displayName,
        ));
      }
    }
    return out;
  }

  Future<void> _launchMaps(BuildContext context) async {
    final address = customer != null
        ? '${customer!.address.street} ${customer!.address.houseNumber}, '
              '${customer!.address.postalCode} ${customer!.address.city}'
        : delivery.deliveryAddressSnapshot.oneLine;
    final encoded = Uri.encodeComponent(address);
    // Universelles `geo:?q=…`-Schema funktioniert auf Android + iOS.
    final uri = Uri.parse(
      'https://www.google.com/maps/search/?api=1&query=$encoded',
    );
    await launchUrl(uri, mode: LaunchMode.externalApplication);
  }

  Future<void> _call(BuildContext context, String phone) async {
    final ok = await launchUrl(Uri(scheme: 'tel', path: phone));
    if (!ok && context.mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Anruf konnte nicht gestartet werden: $phone')),
      );
    }
  }

  /// Einstiegspunkt für den „Anrufen"-Button.
  ///   * Genau eine Nummer ⇒ direkt anrufen.
  ///   * Mehrere Nummern ⇒ Bottom-Sheet, danach anrufen.
  /// Aufgerufen wird die Methode nur, wenn `numbers.isNotEmpty` —
  /// die Validierung sitzt im `build` und schaltet den Button sonst aus.
  Future<void> _onCallTapped(
    BuildContext context,
    List<_CallableNumber> numbers,
  ) async {
    if (numbers.length == 1) {
      await _call(context, numbers.first.value);
      return;
    }
    final picked = await showModalBottomSheet<_CallableNumber>(
      context: context,
      showDragHandle: true,
      builder: (sheetContext) {
        return SafeArea(
          child: ListView(
            shrinkWrap: true,
            children: [
              Padding(
                padding: const EdgeInsets.fromLTRB(16, 4, 16, 12),
                child: Text(
                  'Nummer wählen',
                  style: Theme.of(sheetContext).textTheme.titleMedium,
                ),
              ),
              for (final n in numbers)
                ListTile(
                  leading: Icon(
                    n.kind == ContactKind.mobile
                        ? Icons.smartphone
                        : Icons.call,
                    color: Theme.of(sheetContext).colorScheme.primary,
                  ),
                  title: Text(n.value),
                  subtitle: Text(
                    n.displayName == null
                        ? n.roleLabel
                        : '${n.displayName} · ${n.roleLabel}',
                  ),
                  onTap: () => Navigator.of(sheetContext).pop(n),
                ),
            ],
          ),
        );
      },
    );
    if (picked == null || !context.mounted) return;
    await _call(context, picked.value);
  }

  Future<String?> _askReason(BuildContext context, String title) async {
    final controller = TextEditingController();
    final result = await showDialog<String>(
      context: context,
      builder: (dialogContext) => AlertDialog(
        title: Text(title),
        content: TextField(
          controller: controller,
          autofocus: true,
          decoration: const InputDecoration(
            labelText: 'Grund',
            border: OutlineInputBorder(),
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(dialogContext).pop(null),
            child: const Text('Abbrechen'),
          ),
          FilledButton(
            onPressed: () {
              final text = controller.text.trim();
              if (text.isEmpty) return;
              Navigator.of(dialogContext).pop(text);
            },
            child: const Text('Bestätigen'),
          ),
        ],
      ),
    );
    return result;
  }

  Future<void> _onStatusSelected(
    BuildContext context,
    _StatusAction action,
  ) async {
    final tourBloc = context.read<TourBloc>();
    switch (action) {
      case _StatusAction.hold:
        final reason = await _askReason(context, 'Lieferung pausieren');
        if (reason == null) return;
        tourBloc.add(HoldDelivery(deliveryId: delivery.id, reason: reason));
      case _StatusAction.cancel:
        final reason = await _askReason(context, 'Lieferung abbrechen');
        if (reason == null) return;
        tourBloc.add(CancelDelivery(deliveryId: delivery.id, reason: reason));
      case _StatusAction.resume:
        tourBloc.add(ResumeDelivery(deliveryId: delivery.id));
    }
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final numbers = _collectCallableNumbers();
    final hasPhone = numbers.isNotEmpty;
    final isActive = delivery.state == DeliveryState.active;
    final isHeld = delivery.state == DeliveryState.held;

    return Card(
      margin: EdgeInsets.zero,
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 12),
        child: Row(
          children: [
            Expanded(
              child: _QuickButton(
                icon: Icons.phone,
                label: 'Anrufen',
                enabled: hasPhone,
                onTap: hasPhone ? () => _onCallTapped(context, numbers) : null,
              ),
            ),
            Expanded(
              child: _QuickButton(
                icon: Icons.map_outlined,
                label: 'Maps',
                enabled: true,
                onTap: () => _launchMaps(context),
              ),
            ),
            PopupMenuButton<_StatusAction>(
              icon: Icon(
                Icons.more_vert,
                color: theme.colorScheme.primary,
              ),
              tooltip: 'Status ändern',
              onSelected: (a) => _onStatusSelected(context, a),
              itemBuilder: (context) {
                if (isActive) {
                  return const [
                    PopupMenuItem(
                      value: _StatusAction.hold,
                      child: Row(
                        children: [
                          Icon(Icons.pause_circle_outline,
                              color: Colors.orange),
                          SizedBox(width: 12),
                          Text('Pausieren'),
                        ],
                      ),
                    ),
                    PopupMenuItem(
                      value: _StatusAction.cancel,
                      child: Row(
                        children: [
                          Icon(Icons.cancel_outlined, color: Colors.red),
                          SizedBox(width: 12),
                          Text('Abbrechen'),
                        ],
                      ),
                    ),
                  ];
                }
                if (isHeld) {
                  return const [
                    PopupMenuItem(
                      value: _StatusAction.resume,
                      child: Row(
                        children: [
                          Icon(Icons.play_circle_outline,
                              color: Colors.blueAccent),
                          SizedBox(width: 12),
                          Text('Fortsetzen'),
                        ],
                      ),
                    ),
                  ];
                }
                // canceled / completed: keine Statusänderung mehr.
                return const [
                  PopupMenuItem(
                    enabled: false,
                    child: Text('Keine Aktionen verfügbar'),
                  ),
                ];
              },
            ),
          ],
        ),
      ),
    );
  }
}

class _QuickButton extends StatelessWidget {
  const _QuickButton({
    required this.icon,
    required this.label,
    required this.enabled,
    required this.onTap,
  });

  final IconData icon;
  final String label;
  final bool enabled;
  final VoidCallback? onTap;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return InkWell(
      onTap: enabled ? onTap : null,
      borderRadius: BorderRadius.circular(8),
      child: Padding(
        padding: const EdgeInsets.symmetric(vertical: 4),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            IconButton.filled(
              onPressed: enabled ? onTap : null,
              icon: Icon(icon),
            ),
            Text(
              label,
              style: TextStyle(
                fontSize: 12,
                color: enabled
                    ? theme.colorScheme.onSurface
                    : theme.colorScheme.onSurfaceVariant,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// ─── Sondervereinbarungen + Wunschzeit ──────────────────────────────────

class _AgreementsCard extends StatelessWidget {
  const _AgreementsCard({required this.delivery});
  final Delivery delivery;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final desiredTime = delivery.desiredTime;
    final hasDesired = desiredTime != null && desiredTime.isNotEmpty;
    final agreements = delivery.specialAgreements;
    final hasAgreements = agreements != null && agreements.isNotEmpty;

    return Card(
      margin: EdgeInsets.zero,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            if (hasDesired) ...[
              Row(
                children: [
                  Icon(
                    Icons.schedule,
                    color: theme.colorScheme.primary,
                    size: 28,
                  ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'Wunschtermin',
                          style: TextStyle(
                            fontSize: 12,
                            color: theme.colorScheme.onSurfaceVariant,
                          ),
                        ),
                        Text(
                          desiredTime,
                          style: TextStyle(
                            fontSize: 20,
                            fontWeight: FontWeight.bold,
                            color: theme.colorScheme.primary,
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
              if (hasAgreements) const Divider(height: 24),
            ],
            if (hasAgreements)
              Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Icon(
                    Icons.warning_amber_rounded,
                    color: Colors.amber.shade800,
                    size: 28,
                  ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: Text(
                      agreements,
                      style: const TextStyle(fontSize: 14),
                    ),
                  ),
                ],
              ),
            if (!hasDesired && !hasAgreements)
              Text(
                'Keine Sondervereinbarungen.',
                style: TextStyle(
                  color: theme.colorScheme.onSurfaceVariant,
                  fontStyle: FontStyle.italic,
                ),
              ),
          ],
        ),
      ),
    );
  }
}

// ─── Kunde + Kontakte ───────────────────────────────────────────────────

class _CustomerCard extends StatelessWidget {
  const _CustomerCard({required this.customer, required this.contacts});

  final Customer? customer;
  final List<CustomerContact> contacts;

  Future<void> _call(BuildContext context, String phone) async {
    final ok = await launchUrl(Uri(scheme: 'tel', path: phone));
    if (!ok && context.mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Anruf konnte nicht gestartet werden: $phone')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final c = customer;
    return Card(
      margin: EdgeInsets.zero,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Icon(Icons.person, color: theme.colorScheme.primary),
                const SizedBox(width: 10),
                Expanded(
                  child: Text(
                    c?.name ?? '⟨Unbekannter Kunde⟩',
                    style: const TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.w700,
                    ),
                  ),
                ),
              ],
            ),
            if (c != null) ...[
              const SizedBox(height: 12),
              Row(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Icon(
                    Icons.home_outlined,
                    color: theme.colorScheme.primary,
                  ),
                  const SizedBox(width: 10),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          '${c.address.street} ${c.address.houseNumber}',
                          style: const TextStyle(fontSize: 14),
                        ),
                        Text(
                          '${c.address.postalCode} ${c.address.city}',
                          style: const TextStyle(fontSize: 14),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ],
            if (contacts.isNotEmpty) ...[
              const Divider(height: 24),
              Text(
                'Ansprechpartner',
                style: theme.textTheme.titleSmall?.copyWith(
                  fontWeight: FontWeight.w700,
                ),
              ),
              const SizedBox(height: 8),
              for (final contact in contacts) ...[
                _ContactRow(contact: contact, onCall: _call),
              ],
            ],
          ],
        ),
      ),
    );
  }
}

class _ContactRow extends StatelessWidget {
  const _ContactRow({required this.contact, required this.onCall});

  final CustomerContact contact;
  final Future<void> Function(BuildContext, String) onCall;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final phone = contact.phone;
    final hasPhone = phone != null && phone.isNotEmpty;
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        children: [
          Icon(
            Icons.person_outline,
            size: 18,
            color: theme.colorScheme.primary,
          ),
          const SizedBox(width: 8),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  contact.name,
                  style: const TextStyle(fontWeight: FontWeight.w600),
                ),
                if (hasPhone)
                  Text(
                    phone,
                    style: TextStyle(
                      fontSize: 12,
                      color: theme.colorScheme.onSurfaceVariant,
                    ),
                  )
                else if (contact.email != null)
                  Text(
                    contact.email!,
                    style: TextStyle(
                      fontSize: 12,
                      color: theme.colorScheme.onSurfaceVariant,
                    ),
                  ),
              ],
            ),
          ),
          if (hasPhone)
            IconButton(
              icon: Icon(Icons.call, color: theme.colorScheme.primary),
              tooltip: 'Anrufen',
              onPressed: () => onCall(context, phone),
            ),
        ],
      ),
    );
  }
}

// ─── Artikelliste (inkl. nicht-scanbarer Dienstleistungen) ──────────────

class _ArticleList extends StatelessWidget {
  const _ArticleList({required this.delivery, required this.details});

  final Delivery delivery;
  final TourDetails details;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    // ALLE Items, auch nicht-scanbare Dienstleistungen — Step 1 ist die
    // Übersicht „was geht heute raus". Entfernte werden durchgestrichen
    // mit angezeigt (Fahrer soll wissen, dass da was war).
    // Sortierung: nach Belegzeile, und innerhalb einer Belegzeile der
    // Oberartikel VOR seinen Komponenten — damit Komponenten direkt unter
    // ihrem Oberartikel (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 ?? '');
      });

    if (items.isEmpty) {
      return Card(
        margin: EdgeInsets.zero,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Text(
            'Keine Artikel hinterlegt.',
            style: TextStyle(
              fontStyle: FontStyle.italic,
              color: theme.colorScheme.onSurfaceVariant,
            ),
          ),
        ),
      );
    }

    // Hat sich bei mindestens einem Artikel die tatsächliche Menge geändert
    // (entfernt oder teilweise gutgeschrieben)? Dann ein Banner mit Verweis
    // auf Step 3 „Artikel", wo die Änderungen verwaltet werden.
    final anyChanged = items.any(_quantityChanged);

    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        if (anyChanged) ...[
          const _QuantityChangedBanner(),
          const SizedBox(height: 8),
        ],
        Card(
          margin: EdgeInsets.zero,
          child: Column(
            children: [
              for (int i = 0; i < items.length; i++) ...[
                _ArticleRow(item: items[i], details: details),
                if (i < items.length - 1)
                  const Divider(height: 1, indent: 16, endIndent: 16),
              ],
            ],
          ),
        ),
      ],
    );
  }
}

/// `true`, wenn die tatsächlich auszuliefernde Menge von der ursprünglich
/// bestellten abweicht — also die Position ganz entfernt oder teilweise
/// gutgeschrieben wurde.
bool _quantityChanged(DeliveryItem item) =>
    item.isRemoved || item.scanProgress.creditedQuantity > 0;

/// Tappbares Banner über der Artikelliste: weist darauf hin, dass sich die
/// Menge mindestens eines Artikels geändert hat, und springt zu Step 3
/// („Artikel"), wo die Änderungen sichtbar/verwaltbar sind.
class _QuantityChangedBanner extends StatelessWidget {
  const _QuantityChangedBanner();

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final amber = Colors.amber.shade800;
    return InkWell(
      borderRadius: BorderRadius.circular(8),
      onTap: () => context
          .read<DeliveryWorkflowBloc>()
          .add(const WorkflowGoToStep(WorkflowStep.articles)),
      child: Container(
        padding: const EdgeInsets.all(12),
        decoration: BoxDecoration(
          color: amber.withValues(alpha: 0.10),
          borderRadius: BorderRadius.circular(8),
          border: Border.all(color: amber.withValues(alpha: 0.4)),
        ),
        child: Row(
          children: [
            Icon(Icons.edit_note, color: amber),
            const SizedBox(width: 10),
            Expanded(
              child: Text(
                'Bei mindestens einem Artikel hat sich die Menge geändert. '
                'Details unter Schritt 3 „Artikel".',
                style: theme.textTheme.bodySmall?.copyWith(color: amber),
              ),
            ),
            Icon(Icons.chevron_right, color: amber, size: 20),
          ],
        ),
      ),
    );
  }
}

class _ArticleRow extends StatelessWidget {
  const _ArticleRow({required this.item, required this.details});

  final DeliveryItem item;
  final TourDetails details;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final article = details.articleOf(item.articleId);
    final warehouse = details.warehouseOf(item.warehouseId);
    final isScannable = article?.scannable ?? false;
    final removed = item.isRemoved;
    // Menge tatsächlich verändert (entfernt oder teilweise gutgeschrieben)?
    final changed = _quantityChanged(item);

    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: removed
            ? theme.colorScheme.surfaceContainerHighest
            : theme.colorScheme.primary,
        foregroundColor: removed
            ? theme.colorScheme.onSurfaceVariant
            : theme.colorScheme.onPrimary,
        // Bewusst die URSPRÜNGLICH bestellte Menge (requiredQuantity), nicht
        // die reduzierte — Änderungen werden separat als Hinweis ausgewiesen.
        child: Text(
          '${item.requiredQuantity}×',
          style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
        ),
      ),
      title: Text(
        '${item.isComponent ? '↳ ' : ''}${article?.name ?? '⟨Unbekannter Artikel⟩'}',
        style: TextStyle(
          fontWeight: FontWeight.w600,
          decoration: removed ? TextDecoration.lineThrough : null,
          color: removed ? theme.colorScheme.onSurfaceVariant : null,
        ),
      ),
      subtitle: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            [
              article?.articleNumber ?? item.articleId,
              if (warehouse != null) warehouse.name,
              if (!isScannable) 'Dienstleistung',
              if (item.unitPrice > 0)
                '${item.unitPrice.toStringAsFixed(2)} € / Stück',
            ].join(' · '),
            style: TextStyle(
              fontSize: 12,
              color: theme.colorScheme.onSurfaceVariant,
              decoration: removed ? TextDecoration.lineThrough : null,
            ),
          ),
          if (changed)
            Padding(
              padding: const EdgeInsets.only(top: 2),
              child: Row(
                children: [
                  Icon(Icons.edit_note, size: 14, color: Colors.amber.shade800),
                  const SizedBox(width: 4),
                  Flexible(
                    child: Text(
                      removed
                          ? 'Menge geändert: entfernt (Ursprung ${item.requiredQuantity}×)'
                          : 'Menge geändert: jetzt ${item.deliveredQuantity}× '
                              '(Ursprung ${item.requiredQuantity}×)',
                      style: TextStyle(
                        fontSize: 11,
                        fontWeight: FontWeight.w600,
                        color: Colors.amber.shade800,
                      ),
                    ),
                  ),
                ],
              ),
            ),
        ],
      ),
      trailing: isScannable
          ? Text(
              '${item.scanProgress.scannedQuantity} / ${item.requiredQuantity}',
              style: const TextStyle(
                fontWeight: FontWeight.bold,
              ),
            )
          : null,
    );
  }
}

// ─── Alle Kontaktinfos aus dem ERP ──────────────────────────────────────
//
// Die obige `_CustomerCard` zeigt nur die klassischen Ansprechpartner
// (Stammdaten-Liste pro Kunde). Diese Sektion zeigt die *belegspezifischen*
// Adress-Quellen aus dem ERP: Belegadresse / Lieferadresse / Rechnungs-
// adresse / Ansprechpartner / Kundenstamm — jede mit ihrem eigenen
// Namensblock und allen hinterlegten Telefon-/Mobil-/E-Mail-/Web-Kanälen.
// Sortiert kommen sie vom Backend; das UI bildet sie 1:1 ab.

class _AllContactsCard extends StatelessWidget {
  const _AllContactsCard({required this.sources});

  final List<MergedContactSource> sources;

  Future<void> _launch(BuildContext context, Uri uri, String label) async {
    final ok = await launchUrl(uri);
    if (!ok && context.mounted) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('$label konnte nicht geöffnet werden')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.zero,
      child: Padding(
        padding: const EdgeInsets.symmetric(vertical: 4),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            for (var i = 0; i < sources.length; i++) ...[
              if (i > 0) const Divider(height: 1),
              _ContactSourceTile(
                source: sources[i],
                onLaunch: _launch,
              ),
            ],
          ],
        ),
      ),
    );
  }
}

class _ContactSourceTile extends StatelessWidget {
  const _ContactSourceTile({
    required this.source,
    required this.onLaunch,
  });

  final MergedContactSource source;
  final Future<void> Function(BuildContext, Uri, String) onLaunch;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final channels = source.channels;
    return Padding(
      padding: const EdgeInsets.fromLTRB(16, 12, 16, 12),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Rollen-Label: alle zusammengeführten Rollen mit `·` getrennt
          // (z. B. „Belegadresse · Kundenstamm").
          Text(
            source.rolesLabel,
            style: theme.textTheme.labelLarge?.copyWith(
              color: theme.colorScheme.primary,
              fontWeight: FontWeight.w700,
            ),
          ),
          if (source.displayName != null) ...[
            const SizedBox(height: 2),
            Text(
              source.displayName!,
              style: const TextStyle(fontWeight: FontWeight.w600),
            ),
          ],
          if (source.subtitle != null)
            Text(
              source.subtitle!,
              style: TextStyle(
                fontSize: 12,
                color: theme.colorScheme.onSurfaceVariant,
              ),
            ),
          if (channels.isEmpty) ...[
            const SizedBox(height: 6),
            Text(
              'Keine Telefonnummer oder E-Mail hinterlegt.',
              style: TextStyle(
                fontSize: 12,
                color: theme.colorScheme.onSurfaceVariant,
                fontStyle: FontStyle.italic,
              ),
            ),
          ] else ...[
            const SizedBox(height: 8),
            for (final ch in channels)
              _ChannelRow(channel: ch, onLaunch: onLaunch),
          ],
        ],
      ),
    );
  }
}

class _ChannelRow extends StatelessWidget {
  const _ChannelRow({required this.channel, required this.onLaunch});

  final ContactChannel channel;
  final Future<void> Function(BuildContext, Uri, String) onLaunch;

  // Symbol + Aktion ergeben sich aus dem `kind` — drei Tap-Targets:
  //   phone/mobile → tel:    | email → mailto: | web → https-URL
  // Web-URLs erkennt der Sync 1:1 aus `Adressen.InternetAdresse`; falls
  // dort kein Schema steht (häufiger Fall: „www.kunde.de"), prefixen wir
  // https://. Sonst öffnet `launchUrl` mit relativem URI auf Android nichts.
  ({IconData icon, String semantics, Uri? uri}) _action() {
    switch (channel.kind) {
      case ContactKind.phone:
      case ContactKind.mobile:
        return (
          icon: channel.kind == ContactKind.mobile
              ? Icons.smartphone
              : Icons.call,
          semantics: 'Anrufen',
          uri: Uri(scheme: 'tel', path: channel.value),
        );
      case ContactKind.email:
        return (
          icon: Icons.mail_outline,
          semantics: 'E-Mail schreiben',
          uri: Uri(scheme: 'mailto', path: channel.value),
        );
      case ContactKind.web:
        final raw = channel.value;
        final normalized = raw.startsWith(RegExp(r'https?://'))
            ? raw
            : 'https://$raw';
        return (
          icon: Icons.public,
          semantics: 'Webseite öffnen',
          uri: Uri.tryParse(normalized),
        );
    }
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final action = _action();
    final hasUri = action.uri != null;

    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        children: [
          Icon(action.icon, size: 18, color: theme.colorScheme.primary),
          const SizedBox(width: 8),
          Expanded(
            child: Text(
              channel.value,
              style: const TextStyle(fontSize: 14),
            ),
          ),
          if (hasUri)
            IconButton(
              icon: Icon(action.icon, color: theme.colorScheme.primary),
              tooltip: action.semantics,
              onPressed: () =>
                  onLaunch(context, action.uri!, action.semantics),
            ),
        ],
      ),
    );
  }
}

/// Auswahl-Eintrag für den „Anrufen"-Quick-Action — kapselt eine
/// anrufbare Nummer mit dem nötigen Kontext (Rolle / Name / Icon), aus
/// dem das Bottom-Sheet seine Zeilen baut. Bewusst nur View-lokal:
/// die Domain kennt nur Sources und Channels, das Sheet braucht eine
/// flache, vorgefilterte Liste.
class _CallableNumber {
  const _CallableNumber({
    required this.value,
    required this.kind,
    required this.roleLabel,
    required this.displayName,
  });

  final String value;
  final ContactKind kind;
  final String roleLabel;
  final String? displayName;

  /// Bei einer Dublette (gleiche Nummer aus mehreren Quellen) hängen wir
  /// die zweite Rolle ans Label. Duplikate werden vor dem `withAdditional`
  /// schon im Normalisierungs-Check abgefangen, sodass dasselbe Label nie
  /// zweimal in [roleLabel] landet.
  _CallableNumber withAdditionalRole(String additionalRoleLabel) {
    if (roleLabel.contains(additionalRoleLabel)) return this;
    return _CallableNumber(
      value: value,
      kind: kind,
      roleLabel: '$roleLabel · $additionalRoleLabel',
      displayName: displayName,
    );
  }
}
