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

import '../data/export_import/seed_label_codec.dart';
import '../data/variety_repository.dart';
import '../di/injector.dart';
import '../i18n/strings.g.dart';
import '../services/label_sheet_service.dart';
import 'quantity_kind_l10n.dart';

/// Opens the print-labels sheet for [entries] (already gathered from the
/// current selection): choose how many copies of each label (prefilled from the
/// stored container count) and a label size, then save a PDF sheet of labels —
/// each with a QR that carries the seed's data.
Future<void> showLabelPrintSheet(
  BuildContext context,
  List<SeedLabelEntry> entries,
) {
  return showModalBottomSheet<void>(
    context: context,
    isScrollControlled: true,
    builder: (_) => _LabelPrintSheet(entries: entries),
  );
}

/// Upper bound on copies per label — a printed sheet, not a print run.
const _maxCopies = 99;

class _LabelPrintSheet extends StatefulWidget {
  const _LabelPrintSheet({required this.entries});

  final List<SeedLabelEntry> entries;

  @override
  State<_LabelPrintSheet> createState() => _LabelPrintSheetState();
}

class _LabelPrintSheetState extends State<_LabelPrintSheet> {
  LabelSheetFormat _format = LabelSheetFormat.stickers;
  bool _saving = false;

  /// One editable copy-count per entry, prefilled from its suggested count.
  late final List<int> _copies = [
    for (final e in widget.entries) e.suggestedCopies.clamp(0, _maxCopies),
  ];
  late final List<TextEditingController> _controllers = [
    for (final n in _copies) TextEditingController(text: '$n'),
  ];

  int get _total => _copies.fold(0, (sum, n) => sum + n);

  @override
  void dispose() {
    for (final c in _controllers) {
      c.dispose();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final t = context.t;
    return SafeArea(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              t.printLabels.title,
              style: Theme.of(context).textTheme.titleLarge,
            ),
            const SizedBox(height: 4),
            Text(
              t.printLabels.count(n: _total),
              key: const Key('printLabels.total'),
              style: Theme.of(context).textTheme.bodyMedium,
            ),
            const SizedBox(height: 8),
            // The per-seed copy list can be long; keep the format chooser and
            // the save button always visible by scrolling only this section.
            Flexible(
              child: ConstrainedBox(
                constraints: BoxConstraints(
                  maxHeight: MediaQuery.of(context).size.height * 0.4,
                ),
                child: ListView.builder(
                  shrinkWrap: true,
                  itemCount: widget.entries.length,
                  itemBuilder: (context, i) => _CopyRow(
                    entry: widget.entries[i],
                    controller: _controllers[i],
                    onMinus: _copies[i] > 0 ? () => _bump(i, -1) : null,
                    onPlus: _copies[i] < _maxCopies ? () => _bump(i, 1) : null,
                    onChanged: (value) => _setCopies(i, value),
                  ),
                ),
              ),
            ),
            const Divider(height: 20),
            RadioGroup<LabelSheetFormat>(
              groupValue: _format,
              onChanged: _pick,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: [
                  RadioListTile<LabelSheetFormat>(
                    key: const Key('printLabels.format.stickers'),
                    value: LabelSheetFormat.stickers,
                    contentPadding: EdgeInsets.zero,
                    title: Text(t.printLabels.formatStickers),
                    subtitle: Text(t.printLabels.formatStickersHint),
                  ),
                  RadioListTile<LabelSheetFormat>(
                    key: const Key('printLabels.format.cards'),
                    value: LabelSheetFormat.cards,
                    contentPadding: EdgeInsets.zero,
                    title: Text(t.printLabels.formatCards),
                    subtitle: Text(t.printLabels.formatCardsHint),
                  ),
                ],
              ),
            ),
            const SizedBox(height: 12),
            Align(
              alignment: AlignmentDirectional.centerEnd,
              child: FilledButton.icon(
                key: const Key('printLabels.save'),
                onPressed: (_saving || _total == 0) ? null : _save,
                icon: const Icon(Icons.save_alt_outlined),
                label: Text(t.printLabels.save),
              ),
            ),
          ],
        ),
      ),
    );
  }

  void _pick(LabelSheetFormat? value) {
    if (value != null) setState(() => _format = value);
  }

  /// Steps the count for entry [i] by [delta], syncing the text field.
  void _bump(int i, int delta) {
    final next = (_copies[i] + delta).clamp(0, _maxCopies);
    _controllers[i].text = '$next';
    setState(() => _copies[i] = next);
  }

  /// Applies a typed value (empty → 0), clamped to the allowed range.
  void _setCopies(int i, String value) {
    final parsed = int.tryParse(value) ?? 0;
    setState(() => _copies[i] = parsed.clamp(0, _maxCopies));
  }

  Future<void> _save() async {
    final t = context.t;
    final messenger = ScaffoldMessenger.of(context);
    final navigator = Navigator.of(context);
    final rtl = Directionality.of(context) == TextDirection.rtl;
    setState(() => _saving = true);

    // Expand each entry into its chosen number of identical labels.
    final labels = <LabelSheetLabel>[
      for (var i = 0; i < widget.entries.length; i++)
        for (var c = 0; c < _copies[i]; c++) _toLabel(t, widget.entries[i]),
    ];
    final saved = await getIt<LabelSheetService>().saveLabels(
      labels: labels,
      format: _format,
      suggestedName: 'tanemaki-labels-${_today()}.pdf',
      rtl: rtl,
    );

    navigator.pop();
    messenger.showSnackBar(
      SnackBar(
        content: Text(saved ? t.printLabels.saved : t.printLabels.cancelled),
      ),
    );
  }

  /// Builds one printable label from a [SeedLabelEntry]: the visible fields plus
  /// the QR payload (structured, so a future scan can read it).
  LabelSheetLabel _toLabel(Translations t, SeedLabelEntry e) {
    final origin = _origin(e);
    final details = <String>[
      if (e.harvestYear != null) '${e.harvestYear}',
      ?origin,
      if (e.quantity != null) quantityDisplay(t, e.quantity!),
    ];
    return LabelSheetLabel(
      varietyLabel: e.varietyLabel,
      commonName: e.commonName,
      scientificName: e.scientificName,
      details: details.isEmpty ? null : details.join(' · '),
      qrData: SeedLabelCodec.encode(
        SeedLabelData(
          varietyLabel: e.varietyLabel,
          scientificName: e.scientificName,
          commonName: e.commonName,
          year: e.harvestYear,
          origin: origin,
        ),
      ),
    );
  }

  String? _origin(SeedLabelEntry e) {
    final parts = <String>[
      if (e.originName != null && e.originName!.trim().isNotEmpty)
        e.originName!.trim(),
      if (e.originPlace != null && e.originPlace!.trim().isNotEmpty)
        e.originPlace!.trim(),
    ];
    return parts.isEmpty ? null : parts.join(' · ');
  }

  String _today() => DateTime.now().toIso8601String().substring(0, 10);
}

/// One row of the copy chooser: the seed's name plus a −/number/+ stepper. The
/// number is directly editable so "12 jars" is a quick type, not twelve taps.
class _CopyRow extends StatelessWidget {
  const _CopyRow({
    required this.entry,
    required this.controller,
    required this.onMinus,
    required this.onPlus,
    required this.onChanged,
  });

  final SeedLabelEntry entry;
  final TextEditingController controller;
  final VoidCallback? onMinus;
  final VoidCallback? onPlus;
  final ValueChanged<String> onChanged;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final subtitle = <String>[
      if (entry.commonName != null && entry.commonName!.trim().isNotEmpty)
        entry.commonName!,
      if (entry.harvestYear != null) '${entry.harvestYear}',
    ].join(' · ');
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        children: [
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  entry.varietyLabel,
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: theme.textTheme.bodyLarge,
                ),
                if (subtitle.isNotEmpty)
                  Text(
                    subtitle,
                    maxLines: 1,
                    overflow: TextOverflow.ellipsis,
                    style: theme.textTheme.bodySmall,
                  ),
              ],
            ),
          ),
          const SizedBox(width: 8),
          IconButton(
            key: Key('printLabels.copies.minus.${entry.varietyLabel}'),
            onPressed: onMinus,
            icon: const Icon(Icons.remove_circle_outline),
            visualDensity: VisualDensity.compact,
          ),
          SizedBox(
            width: 44,
            child: TextField(
              key: Key('printLabels.copies.field.${entry.varietyLabel}'),
              controller: controller,
              onChanged: onChanged,
              textAlign: TextAlign.center,
              keyboardType: TextInputType.number,
              inputFormatters: [FilteringTextInputFormatter.digitsOnly],
              decoration: const InputDecoration(
                isDense: true,
                contentPadding: EdgeInsets.symmetric(vertical: 8),
              ),
            ),
          ),
          IconButton(
            key: Key('printLabels.copies.plus.${entry.varietyLabel}'),
            onPressed: onPlus,
            icon: const Icon(Icons.add_circle_outline),
            visualDensity: VisualDensity.compact,
          ),
        ],
      ),
    );
  }
}
