import 'dart:async';
import 'dart:typed_data';

import 'package:commons_core/commons_core.dart';
import 'package:drift/drift.dart' show Value;
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import '../data/variety_repository.dart';
import '../db/enums.dart';

class VarietyDetailState extends Equatable {
  const VarietyDetailState({
    this.detail,
    this.loading = true,
    this.deleted = false,
  });

  final VarietyDetail? detail;
  final bool loading;
  final bool deleted;

  @override
  List<Object?> get props => [detail, loading, deleted];
}

/// Streams one variety's detail and edits it through the repository.
class VarietyDetailCubit extends Cubit<VarietyDetailState> {
  VarietyDetailCubit(this._repo, this.varietyId)
    : super(const VarietyDetailState()) {
    _sub = _repo
        .watchVariety(varietyId)
        .listen(
          (d) => emit(
            VarietyDetailState(
              detail: d,
              loading: false,
              deleted: state.deleted,
            ),
          ),
        );
  }

  final VarietyRepository _repo;
  final String varietyId;
  late final StreamSubscription<VarietyDetail?> _sub;

  Future<void> updateFields({
    String? label,
    String? category,
    String? notes,
    bool? isOrganic,
    bool? needsReproduction,
    Value<int?> sowMonths = const Value.absent(),
    Value<int?> transplantMonths = const Value.absent(),
    Value<int?> floweringMonths = const Value.absent(),
    Value<int?> fruitingMonths = const Value.absent(),
    Value<int?> seedHarvestMonths = const Value.absent(),
  }) => _repo.updateVariety(
    id: varietyId,
    label: label,
    category: category,
    notes: notes,
    isOrganic: isOrganic,
    needsReproduction: needsReproduction,
    sowMonths: sowMonths,
    transplantMonths: transplantMonths,
    floweringMonths: floweringMonths,
    fruitingMonths: fruitingMonths,
    seedHarvestMonths: seedHarvestMonths,
  );

  Future<void> addLot({
    LotType type = LotType.seed,
    int? year,
    int? month,
    Quantity? quantity,
    Presentation? presentation,
    String? originName,
    String? originPlace,
    Abundance? abundance,
    PreservationFormat? preservationFormat,
    OfferStatus offerStatus = OfferStatus.private,
  }) => _repo.addLot(
    varietyId: varietyId,
    type: type,
    harvestYear: year,
    harvestMonth: month,
    quantity: quantity,
    presentation: presentation,
    originName: originName,
    originPlace: originPlace,
    abundance: abundance,
    preservationFormat: preservationFormat,
    offerStatus: offerStatus,
  );

  Future<void> updateLot({
    required String lotId,
    required LotType type,
    int? year,
    int? month,
    Quantity? quantity,
    Presentation? presentation,
    String? originName,
    String? originPlace,
    Abundance? abundance,
    PreservationFormat? preservationFormat,
    OfferStatus offerStatus = OfferStatus.private,
  }) => _repo.updateLot(
    lotId: lotId,
    type: type,
    harvestYear: year,
    harvestMonth: month,
    quantity: quantity,
    presentation: presentation,
    originName: originName,
    originPlace: originPlace,
    abundance: abundance,
    preservationFormat: preservationFormat,
    offerStatus: offerStatus,
  );

  Future<void> deleteLot(String lotId) => _repo.softDeleteLot(lotId);

  Future<void> addVernacularName(String name) =>
      _repo.addVernacularName(varietyId, name);

  Future<void> removeVernacularName(String nameId) =>
      _repo.removeVernacularName(nameId);

  Future<void> addPhoto(Uint8List bytes) => _repo.addPhoto(varietyId, bytes);

  Future<void> removePhoto(String attachmentId) =>
      _repo.removePhoto(attachmentId);

  Future<void> setPreferredPhoto(String attachmentId) =>
      _repo.setPreferredPhoto(varietyId, attachmentId);

  Future<void> addExternalLink(String url, {String? title}) =>
      _repo.addExternalLink(varietyId, url, title: title);

  Future<void> removeExternalLink(String linkId) =>
      _repo.removeExternalLink(linkId);

  Future<void> linkSpecies(String speciesId) =>
      _repo.linkSpecies(varietyId, speciesId);

  Future<void> addGerminationTest({
    required String lotId,
    int? testedOn,
    int? sampleSize,
    int? germinatedCount,
  }) => _repo.addGerminationTest(
    lotId: lotId,
    testedOn: testedOn,
    sampleSize: sampleSize,
    germinatedCount: germinatedCount,
  );

  Future<void> addConditionCheck({
    required String lotId,
    int? checkedOn,
    int? containerCount,
    DesiccantState? desiccantState,
  }) => _repo.addConditionCheck(
    lotId: lotId,
    checkedOn: checkedOn,
    containerCount: containerCount,
    desiccantState: desiccantState,
  );

  Future<void> deleteVariety() async {
    await _repo.softDeleteVariety(varietyId);
    emit(
      VarietyDetailState(detail: state.detail, loading: false, deleted: true),
    );
  }

  @override
  Future<void> close() async {
    await _sub.cancel();
    return super.close();
  }
}
