/// An ordered sequence where the chain, not the step, is the unit of
/// completion. Breaking mid-way logs partial.
class RoutineChain {
  String? id;

  String title;

  List<RoutineStep> steps;

  /// Index of the step reached when the chain last broke; -1 when clean.
  int lastBreakIndex;

  RoutineChain({
    this.id,
    this.title = "",
    List<RoutineStep>? steps,
    this.lastBreakIndex = -1,
  }) : steps = steps ?? <RoutineStep>[];

  factory RoutineChain.fromJson(Map<String, dynamic> json) {
    return RoutineChain(
      id: json['id'],
      title: json['title'] ?? "",
      steps: json['steps'] == null
          ? <RoutineStep>[]
          : (json['steps'] as List)
              .map((item) => RoutineStep.fromJson(item))
              .toList(),
      lastBreakIndex: json['lastBreakIndex'] ?? -1,
    );
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data['id'] = id;
    data['title'] = title;
    data['steps'] = steps.map((item) => item.toJson()).toList();
    data['lastBreakIndex'] = lastBreakIndex;
    return data;
  }

  int get completedSteps {
    return steps.where((step) => step.completed).length;
  }

  /// 0..1 — a partially run chain is recorded as partial, not as done.
  double get partialCompletion {
    if (steps.isEmpty) {
      return 0;
    }
    return completedSteps / steps.length;
  }

  bool get complete {
    return steps.isNotEmpty && completedSteps == steps.length;
  }
}

class RoutineStep {
  String? id;

  String title;

  int order;

  int timerSeconds;

  bool completed;

  RoutineStep({
    this.id,
    this.title = "",
    this.order = 0,
    this.timerSeconds = 0,
    this.completed = false,
  });

  factory RoutineStep.fromJson(Map<String, dynamic> json) {
    return RoutineStep(
      id: json['id'],
      title: json['title'] ?? "",
      order: json['order'] ?? 0,
      timerSeconds: json['timerSeconds'] ?? 0,
      completed: json['completed'] ?? false,
    );
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data['id'] = id;
    data['title'] = title;
    data['order'] = order;
    data['timerSeconds'] = timerSeconds;
    data['completed'] = completed;
    return data;
  }
}
