//Unknown
final FriendicaVersion unknown = FriendicaVersion(DateTime(1970, 01));

class FriendicaVersion implements Comparable<FriendicaVersion> {
  final DateTime releaseDate;
  final String extra;

  FriendicaVersion(this.releaseDate, {this.extra = ''});

  factory FriendicaVersion.fromMastodonVersionString(String? text) {
    if (text == null) {
      return unknown;
    }

    final elements = text.split(RegExp('\\s+'));
    final versionString = elements.last.substring(0, elements.last.length - 1);
    return FriendicaVersion.fromVersionString(versionString);
  }

  factory FriendicaVersion.fromVersionString(String? text) {
    if (text == null) {
      return unknown;
    }

    final elements = text.trim().split('.');
    if (elements.length < 2) {
      return unknown;
    }

    final year = int.tryParse(elements[0]);
    if (year == null) {
      return unknown;
    }

    if (year < 2018) {
      return unknown;
    }

    int? month = int.tryParse(elements[1]);
    String extra = '';
    if (month == null) {
      final secondaryFields = elements[1].split(RegExp('\\D+'));
      month = int.tryParse(secondaryFields.first) ?? 1;
      extra = secondaryFields.sublist(1).join('-');
    }

    return FriendicaVersion(DateTime(year, month), extra: extra);
  }

  bool operator >(FriendicaVersion other) {
    return compareTo(other) > 0;
  }

  bool operator >=(FriendicaVersion other) {
    return compareTo(other) >= 0;
  }

  bool operator <(FriendicaVersion other) {
    return compareTo(other) < 0;
  }

  bool operator <=(FriendicaVersion other) {
    return compareTo(other) <= 0;
  }

  @override
  int compareTo(FriendicaVersion other) {
    if (releaseDate == other.releaseDate) {
      final subVersion = int.tryParse(extra);
      final otherSubVersion = int.tryParse(other.extra);
      if (subVersion == null && otherSubVersion == null) {
        return extra.compareTo(other.extra);
      }

      if (subVersion == null && otherSubVersion != null) {
        return -1;
      }

      if (subVersion != null && otherSubVersion == null) {
        return 1;
      }

      return subVersion!.compareTo(otherSubVersion!);
    }
    return releaseDate.compareTo(other.releaseDate);
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is FriendicaVersion &&
          runtimeType == other.runtimeType &&
          releaseDate == other.releaseDate &&
          extra == other.extra;

  @override
  int get hashCode => releaseDate.hashCode ^ extra.hashCode;

  @override
  String toString() {
    return 'FriendicaVersion{releaseDate: $releaseDate, extra: $extra}';
  }

  String toVersionString() {
    final monthString = releaseDate.month.toString().padLeft(2, '0');
    final extraString = extra.isEmpty ? '' : '-$extra';
    return '${releaseDate.year}.$monthString$extraString';
  }
}

// Known Versions
// 2018 Versions
final FriendicaVersion v2018_05 = FriendicaVersion(DateTime(2018, 05));
final FriendicaVersion v2018_09 = FriendicaVersion(DateTime(2018, 09));

// 2019 Versions
final FriendicaVersion v2019_01 = FriendicaVersion(DateTime(2019, 01));
final FriendicaVersion v2019_03 = FriendicaVersion(DateTime(2019, 03));
final FriendicaVersion v2019_04 = FriendicaVersion(DateTime(2019, 04));
final FriendicaVersion v2019_06 = FriendicaVersion(DateTime(2019, 06));
final FriendicaVersion v2019_09 = FriendicaVersion(DateTime(2019, 09));
final FriendicaVersion v2019_12 = FriendicaVersion(DateTime(2019, 12));

// 2020 Versions
final FriendicaVersion v2020_03 = FriendicaVersion(DateTime(2020, 03));
final FriendicaVersion v2020_07 = FriendicaVersion(DateTime(2020, 07));
final FriendicaVersion v2020_07_01 = FriendicaVersion(
  DateTime(2020, 07),
  extra: '1',
);
final FriendicaVersion v2020_09 = FriendicaVersion(DateTime(2020, 09));
final FriendicaVersion v2020_09_01 = FriendicaVersion(
  DateTime(2020, 09),
  extra: '1',
);

// 2021 Versions
final FriendicaVersion v2021_01 = FriendicaVersion(DateTime(2021, 01));
final FriendicaVersion v2021_04 = FriendicaVersion(DateTime(2021, 04));
final FriendicaVersion v2021_07 = FriendicaVersion(DateTime(2021, 07));
final FriendicaVersion v2021_09 = FriendicaVersion(DateTime(2021, 09));

// 2022 Versions
final FriendicaVersion v2022_02 = FriendicaVersion(DateTime(2022, 02));
final FriendicaVersion v2022_03 = FriendicaVersion(DateTime(2022, 03));
final FriendicaVersion v2022_06 = FriendicaVersion(DateTime(2022, 06));
final FriendicaVersion v2022_10 = FriendicaVersion(DateTime(2022, 10));
final FriendicaVersion v2022_12 = FriendicaVersion(DateTime(2022, 12));

// 2023 Versions
final FriendicaVersion v2023_01 = FriendicaVersion(DateTime(2023, 01));
final FriendicaVersion v2023_04 = FriendicaVersion(DateTime(2023, 04));
final FriendicaVersion v2023_04_01 = FriendicaVersion(
  DateTime(2023, 04),
  extra: '1',
);
final FriendicaVersion v2023_05 = FriendicaVersion(DateTime(2023, 05));
final FriendicaVersion v2023_09 = FriendicaVersion(DateTime(2023, 09));

final knownFriendicaVersions = [
//  2018 Versions
  v2018_05,
  v2018_05,
  v2018_09,

// 2019 Versions
  v2019_01,
  v2019_03,
  v2019_04,
  v2019_06,
  v2019_09,
  v2019_12,

// 2020 Versions
  v2020_03,
  v2020_07_01,
  v2020_09,
  v2020_09_01,

// 2021 Versions
  v2021_01,
  v2021_04,
  v2021_07,
  v2021_09,

// 2022 Versions
  v2022_02,
  v2022_03,
  v2022_06,
  v2022_10,
  v2022_12,

// 2023 Versions
  v2023_01,
  v2023_04,
  v2023_04_01,
  v2023_05,
  v2023_09,
];

FriendicaVersion latestVersion() => knownFriendicaVersions.last;
