import 'package:equatable/equatable.dart';

/// The seed facts a printed label carries in its QR code — just enough to
/// identify the seed offline, so the data travels on the physical packet with
/// no server and no account. Kept deliberately small so the QR stays scannable
/// at sticker size.
class SeedLabelData extends Equatable {
  const SeedLabelData({
    required this.varietyLabel,
    this.scientificName,
    this.commonName,
    this.year,
    this.origin,
  });

  /// The variety's label, as its keeper writes it (e.g. "Acelga de Perales").
  final String varietyLabel;

  /// Scientific name of the linked species, if any (e.g. "Beta vulgaris").
  final String? scientificName;

  /// The species' common name in the keeper's locale (e.g. "Acelga").
  final String? commonName;

  /// Harvest year of the batch, if known.
  final int? year;

  /// Where the seed came from (origin name and/or place), if recorded.
  final String? origin;

  @override
  List<Object?> get props => [
    varietyLabel,
    scientificName,
    commonName,
    year,
    origin,
  ];
}

/// Encodes/decodes [SeedLabelData] as a compact, versioned `tanemaki://seed`
/// URI — self-describing and parseable, so a future scan-to-import feature can
/// read a label a keeper printed today. Unicode and RTL text are percent-encoded
/// by [Uri], so any QR reader round-trips them safely.
///
/// Shape: `tanemaki://seed?v=<variety>&s=<scientific>&c=<common>&y=<year>&o=<origin>`
/// Absent fields are omitted, keeping the payload (and the QR) as small as the
/// data allows.
abstract final class SeedLabelCodec {
  static const _scheme = 'tanemaki';
  static const _host = 'seed';

  static String encode(SeedLabelData data) {
    final params = <String, String>{
      'v': data.varietyLabel,
      if (_present(data.scientificName)) 's': data.scientificName!.trim(),
      if (_present(data.commonName)) 'c': data.commonName!.trim(),
      if (data.year != null) 'y': '${data.year}',
      if (_present(data.origin)) 'o': data.origin!.trim(),
    };
    return Uri(
      scheme: _scheme,
      host: _host,
      queryParameters: params,
    ).toString();
  }

  /// Parses a `tanemaki://seed` URI back to [SeedLabelData]. Returns null when
  /// [input] is not a well-formed seed label (wrong scheme/host, or no variety).
  static SeedLabelData? decode(String input) {
    final uri = Uri.tryParse(input.trim());
    if (uri == null || uri.scheme != _scheme || uri.host != _host) return null;
    final q = uri.queryParameters;
    final variety = q['v']?.trim();
    if (variety == null || variety.isEmpty) return null;
    final year = q['y'];
    return SeedLabelData(
      varietyLabel: variety,
      scientificName: _clean(q['s']),
      commonName: _clean(q['c']),
      year: year == null ? null : int.tryParse(year),
      origin: _clean(q['o']),
    );
  }

  static bool _present(String? value) => value != null && value.trim().isNotEmpty;

  static String? _clean(String? value) {
    final trimmed = value?.trim();
    return (trimmed == null || trimmed.isEmpty) ? null : trimmed;
  }
}
