part of '../entities.dart';

/// Created by Haoyi on 2023/10/9

class DailyChallengeStatus {
  static const int idle = 0;
  static const int progressing = 1;
  static const int completed = 2;
}

@JsonSerializable()
class DailyChallengeEntity implements Identifiable {
  static const tbName = "daily";
  static const dbId = "id";

  static const dbStatus = "status";
  static const dbRawId = "rawId";
  static const dbYear = "yr";
  static const dbYearMonth = "ym";
  static const dbYearMonthDay = "ymd";
  static const dbProgress = "progress";
  static const dbCompleteAt = "cpt";
  static const dbUpdateAt = "upt";

  @override
  @JsonKey(name: dbId)
  final String id;

  @JsonKey(name: dbRawId)
  final String rawId;

  @JsonKey(name: dbStatus, defaultValue: 0)
  final int status;

  @JsonKey(name: dbYear, defaultValue: 0)
  final int year;

  @JsonKey(name: dbYearMonth, defaultValue: 0)
  final int yearMonth;

  @JsonKey(name: dbYearMonthDay, defaultValue: 0)
  final int yearMonthDay;

  @JsonKey(name: dbProgress, defaultValue: 0)
  final int progress;

  @JsonKey(name: dbCompleteAt, defaultValue: 0)
  final int completeAt;

  @JsonKey(name: dbUpdateAt, defaultValue: 0)
  final int updateAt;

  DailyChallengeEntity(
      {required this.id,
      required this.rawId,
      required this.status,
      required this.progress,
      required this.year,
      required this.yearMonth,
      required this.yearMonthDay,
      required this.completeAt,
      required this.updateAt});

  static DailyChallengeEntity fromState(
      DateTime focusDate, DailyChallengeState state) {
    final status = state.progress >= 100
        ? DailyChallengeStatus.completed
        : DailyChallengeStatus.progressing;
    final yyyyMMdd = DateTimeUtils.generateYearMonthDayNum(focusDate);
    return DailyChallengeEntity(
        id: "$yyyyMMdd-${state.id}",
        rawId: state.id,
        status: state.progress >= 100
            ? DailyChallengeStatus.completed
            : DailyChallengeStatus.progressing,
        progress: state.progress.clamp(0, 100),
        year: focusDate.year,
        yearMonth: DateTimeUtils.generateYearMonthNum(focusDate),
        yearMonthDay: DateTimeUtils.generateYearMonthDayNum(focusDate),
        completeAt: status == DailyChallengeStatus.completed ? state.at : 0,
        updateAt: state.at);
  }

  factory DailyChallengeEntity.fromMap(Map<String, dynamic> json) =>
      _$DailyChallengeEntityFromJson(json);

  Map<String, dynamic> toMap() => _$DailyChallengeEntityToJson(this);

  static Future createTable(Transaction delegate) async {
    // v1
    const v1Fields = "$dbId TEXT PRIMARY KEY,"
        "$dbRawId TEXT NOT NULL,"
        "$dbStatus INTEGER NOT NULL  DEFAULT ${DailyChallengeStatus.idle},"
        "$dbProgress INTEGER NOT NULL DEFAULT 0,"
        "$dbYear INTEGER NOTE NULL,"
        "$dbYearMonth INTEGER NOT NULL,"
        "$dbYearMonthDay INTEGER NOT NULL,"
        "$dbCompleteAt INTEGER NOT NULL,"
        "$dbUpdateAt INTEGER NOT NULL";

    const cmd = "CREATE TABLE $tbName ("
        "$v1Fields"
        ");";

    Log.d("#### cmd: $cmd");

    await delegate.execute(cmd);
    await delegate.execute("CREATE INDEX challenge_idx ON $tbName ($dbId);");
    await delegate
        .execute("CREATE INDEX challenge_ym_idx ON $tbName ($dbYearMonth)");
    await delegate
        .execute("CREATE INDEX challenge_yr_idx ON $tbName ($dbYear)");
  }

  @override
  String toString() {
    return 'DailyChallengeEntity{id: $id, status: $status, progress: $progress year: $year, yearMonth: $yearMonth, completeAt: $completeAt, updateAt: $updateAt}';
  }
}
