import 'package:flutter_test/flutter_test.dart';
import 'package:tane/data/export_import/inventory_csv_codec.dart';
import 'package:tane/data/export_import/inventory_snapshot.dart';
import 'package:tane/db/database.dart';
import 'package:tane/db/enums.dart';

void main() {
  const codec = InventoryCsvCodec();

  group('decode (additive CSV import)', () {
    test('a minimal one-column list only needs variety_label', () {
      final csv = 'variety_label\r\nGrandma tomato\r\nPurple carrot\r\n';
      final result = codec.decode(csv);
      expect(result.skippedRows, 0);
      expect(result.varieties.map((v) => v.label), [
        'Grandma tomato',
        'Purple carrot',
      ]);
      // No lot columns → no lots.
      expect(result.varieties.first.lots, isEmpty);
    });

    test('skips rows without a variety_label', () {
      final csv =
          'variety_label,category\r\n,Solanaceae\r\nTomato,Solanaceae\r\n';
      final result = codec.decode(csv);
      expect(result.skippedRows, 1);
      expect(result.varieties, hasLength(1));
      expect(result.varieties.single.label, 'Tomato');
    });

    test('maps columns by header name regardless of order', () {
      final csv =
          'category,variety_label,harvest_year,lot_type\r\n'
          'Solanaceae,Tomato,2024,seed\r\n';
      final v = codec.decode(csv).varieties.single;
      expect(v.label, 'Tomato');
      expect(v.category, 'Solanaceae');
      expect(v.lots.single.harvestYear, 2024);
      expect(v.lots.single.type, LotType.seed);
    });

    test('ignores unknown columns', () {
      final csv = 'variety_label,made_up_column\r\nTomato,whatever\r\n';
      final v = codec.decode(csv).varieties.single;
      expect(v.label, 'Tomato');
    });

    test('unknown enums fall back: lot_type→seed, offer_status→private, '
        'quantity_kind dropped', () {
      final csv =
          'variety_label,lot_type,offer_status,quantity_kind\r\n'
          'Tomato,spaceship,gift,truckload\r\n';
      final lot = codec.decode(csv).varieties.single.lots.single;
      expect(lot.type, LotType.seed);
      expect(lot.offerStatus, OfferStatus.private);
      expect(lot.quantityKind, isNull);
    });

    test('keeps a valid quantity_kind and parses precise/label', () {
      final csv =
          'variety_label,quantity_kind,quantity_precise,quantity_label\r\n'
          'Maize,cob,3,a handful\r\n';
      final lot = codec.decode(csv).varieties.single.lots.single;
      expect(lot.quantityKind, 'cob');
      expect(lot.quantityPrecise, 3.0);
      expect(lot.quantityLabel, 'a handful');
    });

    test(
      'rows sharing a variety_id collapse into one variety with many lots',
      () {
        final csv =
            'variety_id,variety_label,lot_type,harvest_year\r\n'
            'v1,Tomato,seed,2023\r\n'
            'v1,Tomato,seed,2024\r\n'
            'v2,Carrot,seed,2024\r\n';
        final result = codec.decode(csv);
        expect(result.varieties, hasLength(2));
        final tomato = result.varieties.firstWhere((v) => v.label == 'Tomato');
        expect(tomato.lots.map((l) => l.harvestYear), [2023, 2024]);
      },
    );

    test('rows without a variety_id each become their own variety', () {
      final csv = 'variety_label,lot_type\r\nTomato,seed\r\nTomato,plant\r\n';
      final result = codec.decode(csv);
      expect(result.varieties, hasLength(2));
    });

    test('parses quoted fields with commas, doubled quotes and newlines', () {
      final csv =
          'variety_label,variety_notes\r\n'
          '"Bean, ""the best""","line one\nline two"\r\n';
      final v = codec.decode(csv).varieties.single;
      expect(v.label, 'Bean, "the best"');
      expect(v.notes, 'line one\nline two');
    });

    test('splits vernacular names and links back out', () {
      final csv =
          'variety_label,vernacular_names,external_links\r\n'
          'Tomato,"tomate (es); granny tomato","Wiki|https://example.org"\r\n';
      final v = codec.decode(csv).varieties.single;
      expect(v.vernacularNames.map((n) => n.name), ['tomate', 'granny tomato']);
      expect(v.vernacularNames.first.language, 'es');
      expect(v.links.single.url, 'https://example.org');
      expect(v.links.single.title, 'Wiki');
    });

    test('tolerates \\n-only line endings and a missing trailing newline', () {
      final csv = 'variety_label\nTomato\nCarrot';
      final result = codec.decode(csv);
      expect(result.varieties.map((v) => v.label), ['Tomato', 'Carrot']);
    });

    test('an empty or header-only file yields nothing', () {
      expect(codec.decode('').varieties, isEmpty);
      expect(codec.decode('variety_label\r\n').varieties, isEmpty);
    });
  });

  group('round-trip with the export encoder', () {
    Variety variety() => Variety(
      id: 'var-1',
      createdAt: 0,
      updatedAt: '000000000001000:00000:node-a',
      lastAuthor: 'node-a',
      isDeleted: false,
      schemaRowVersion: 1,
      label: 'Grandma tomato',
      speciesId: 'sp-1',
      cultivarName: 'Marmande',
      category: 'Solanaceae',
      notes: 'heirloom',
      isDraft: false,
      isOrganic: false,
      needsReproduction: false,
    );

    Lot lot({String id = 'lot-1'}) => Lot(
      id: id,
      createdAt: 0,
      updatedAt: '000000000002000:00000:node-a',
      lastAuthor: 'node-a',
      isDeleted: false,
      schemaRowVersion: 1,
      varietyId: 'var-1',
      type: LotType.seed,
      harvestYear: 2024,
      harvestMonth: 9,
      quantityKind: 'cob',
      quantityPrecise: 2,
      quantityLabel: null,
      presentation: null,
      storageLocation: 'fridge',
      offerStatus: OfferStatus.shared,
      seedbankId: null,
    );

    test('encode → decode preserves variety fields and both lots', () {
      final csv = codec.encode(
        InventorySnapshot(
          varieties: [variety()],
          lots: [
            lot(),
            lot(id: 'lot-2'),
          ],
          speciesNamesById: const {'sp-1': 'Solanum lycopersicum'},
        ),
      );
      final v = codec.decode(csv).varieties.single;
      expect(v.label, 'Grandma tomato');
      expect(v.category, 'Solanaceae');
      expect(v.cultivarName, 'Marmande');
      expect(v.notes, 'heirloom');
      expect(v.scientificName, 'Solanum lycopersicum');
      expect(v.lots, hasLength(2));
      final l = v.lots.first;
      expect(l.type, LotType.seed);
      expect(l.harvestYear, 2024);
      expect(l.harvestMonth, 9);
      expect(l.quantityKind, 'cob');
      expect(l.quantityPrecise, 2.0);
      expect(l.storageLocation, 'fridge');
      expect(l.offerStatus, OfferStatus.shared);
    });
  });
}
