import 'dart:typed_data';

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();

  Variety variety({
    String id = 'var-1',
    String label = 'Grandma tomato',
    String? notes,
  }) => Variety(
    id: id,
    createdAt: 0,
    updatedAt: '000000000001000:00000:node-a',
    lastAuthor: 'node-a',
    isDeleted: false,
    schemaRowVersion: 1,
    label: label,
    speciesId: 'sp-1',
    cultivarName: null,
    category: 'Solanaceae',
    notes: notes,
    isDraft: false,
    isOrganic: false,
    needsReproduction: false,
  );

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

  List<String> rowsOf(String csv) => csv.trimRight().split('\r\n');

  test('emits a header and one row per lot', () {
    final csv = codec.encode(
      InventorySnapshot(
        varieties: [variety()],
        lots: [
          lot(),
          lot(id: 'lot-2'),
        ],
        speciesNamesById: const {'sp-1': 'Solanum lycopersicum'},
      ),
    );
    final rows = rowsOf(csv);
    expect(rows, hasLength(3));
    expect(rows.first, startsWith('variety_id,variety_label,category'));
    expect(rows[1], contains('lot-1'));
    expect(rows[1], contains('Solanum lycopersicum'));
    expect(rows[1], contains('cob'));
    expect(rows[2], contains('lot-2'));
  });

  test('a variety without lots still gets one row', () {
    final csv = codec.encode(InventorySnapshot(varieties: [variety()]));
    final rows = rowsOf(csv);
    expect(rows, hasLength(2));
    expect(rows[1], startsWith('var-1,Grandma tomato,Solanaceae'));
    // Same cell count as the header even with empty lot columns.
    expect(rows[1].split(',').length, rows.first.split(',').length);
  });

  test('escapes commas, quotes and newlines per RFC 4180', () {
    final csv = codec.encode(
      InventorySnapshot(
        varieties: [
          variety(label: 'Bean, "the best"', notes: 'line one\nline two'),
        ],
      ),
    );
    expect(csv, contains('"Bean, ""the best"""'));
    expect(csv, contains('"line one\nline two"'));
  });

  test('joins vernacular names and links; never includes photo bytes', () {
    final snapshot = InventorySnapshot(
      varieties: [variety()],
      vernacularNames: const [
        VarietyVernacularName(
          id: 'n1',
          createdAt: 0,
          updatedAt: '000000000001000:00000:node-a',
          lastAuthor: 'node-a',
          isDeleted: false,
          schemaRowVersion: 1,
          varietyId: 'var-1',
          name: 'tomate de la abuela',
          language: 'es',
          region: null,
        ),
        VarietyVernacularName(
          id: 'n2',
          createdAt: 0,
          updatedAt: '000000000001000:00001:node-a',
          lastAuthor: 'node-a',
          isDeleted: false,
          schemaRowVersion: 1,
          varietyId: 'var-1',
          name: 'granny tomato',
          language: null,
          region: null,
        ),
      ],
      externalLinks: const [
        ExternalLink(
          id: 'l1',
          createdAt: 0,
          updatedAt: '000000000001000:00002:node-a',
          lastAuthor: 'node-a',
          isDeleted: false,
          schemaRowVersion: 1,
          parentType: ParentType.variety,
          parentId: 'var-1',
          url: 'https://example.org',
          title: 'Wiki',
        ),
      ],
      attachments: [
        Attachment(
          id: 'a1',
          createdAt: 0,
          updatedAt: '000000000001000:00003:node-a',
          lastAuthor: 'node-a',
          isDeleted: false,
          schemaRowVersion: 1,
          parentType: ParentType.variety,
          parentId: 'var-1',
          kind: AttachmentKind.photo,
          uri: null,
          bytes: Uint8List.fromList([9, 9, 9]),
          mimeType: 'image/jpeg',
          sortOrder: 0,
        ),
      ],
    );
    final csv = codec.encode(snapshot);
    expect(csv, contains('tomate de la abuela (es); granny tomato'));
    expect(csv, contains('Wiki|https://example.org'));
    expect(csv, isNot(contains('9,9,9')));
    expect(csv.toLowerCase(), isNot(contains('base64')));
  });

  test('reports the latest germination rate per lot', () {
    final csv = codec.encode(
      InventorySnapshot(
        varieties: [variety()],
        lots: [lot()],
        germinationTests: const [
          GerminationTest(
            id: 'g-old',
            createdAt: 0,
            updatedAt: '000000000001000:00000:node-a',
            lastAuthor: 'node-a',
            isDeleted: false,
            schemaRowVersion: 1,
            lotId: 'lot-1',
            testedOn: 100,
            sampleSize: 10,
            germinatedCount: 2,
            notes: null,
          ),
          GerminationTest(
            id: 'g-new',
            createdAt: 0,
            updatedAt: '000000000001000:00001:node-a',
            lastAuthor: 'node-a',
            isDeleted: false,
            schemaRowVersion: 1,
            lotId: 'lot-1',
            testedOn: 200,
            sampleSize: 10,
            germinatedCount: 8,
            notes: null,
          ),
        ],
      ),
    );
    expect(csv, contains('0.80'));
    expect(csv, isNot(contains('0.20')));
  });
}
