import 'package:uuid/uuid.dart';

import '../connection.dart';
import 'string_filter.dart';

enum TimelineEntryFilterAction {
  hide,
  warn,
  ;

  factory TimelineEntryFilterAction.parse(String? value) {
    return TimelineEntryFilterAction.values.firstWhere(
      (v) => v.name == value,
      orElse: () => warn,
    );
  }

  String toLabel() {
    switch (this) {
      case TimelineEntryFilterAction.hide:
        return 'Hide';
      case TimelineEntryFilterAction.warn:
        return 'Warn';
    }
  }

  String toVerb() {
    switch (this) {
      case TimelineEntryFilterAction.hide:
        return 'Hiding';
      case TimelineEntryFilterAction.warn:
        return 'Warning';
    }
  }
}

class TimelineEntryFilter {
  final String id;
  final TimelineEntryFilterAction action;
  final String name;
  final bool enabled;
  final List<StringFilter> authorFilters;
  final List<StringFilter> domainFilters;
  final List<StringFilter> keywordFilters;
  final List<StringFilter> hashtagFilters;

  const TimelineEntryFilter({
    required this.id,
    required this.action,
    required this.name,
    required this.enabled,
    required this.authorFilters,
    required this.domainFilters,
    required this.keywordFilters,
    required this.hashtagFilters,
  });

  TimelineEntryFilter copy({
    String? id,
    TimelineEntryFilterAction? action,
    String? name,
    bool? enabled,
    List<StringFilter>? authorFilters,
    List<StringFilter>? domainFilters,
    List<StringFilter>? keywordFilters,
    List<StringFilter>? hashtagFilters,
  }) =>
      TimelineEntryFilter(
        id: id ?? this.id,
        action: action ?? this.action,
        name: name ?? this.name,
        enabled: enabled ?? this.enabled,
        authorFilters: authorFilters ?? this.authorFilters,
        domainFilters: domainFilters ?? this.domainFilters,
        keywordFilters: keywordFilters ?? this.keywordFilters,
        hashtagFilters: hashtagFilters ?? this.hashtagFilters,
      );

  factory TimelineEntryFilter.create({
    String? id,
    required TimelineEntryFilterAction action,
    required String name,
    required bool enabled,
    List<Connection> authors = const [],
    List<String> domains = const [],
    List<String> keywords = const [],
    List<String> hashtags = const [],
  }) {
    return TimelineEntryFilter(
      id: id ?? const Uuid().v4(),
      action: action,
      name: name,
      enabled: enabled,
      authorFilters: authors
          .map((a) =>
              StringFilter(filterString: a.id, type: ComparisonType.equals))
          .toList(),
      domainFilters: domains
          .map((d) => d.startsWith('*')
              ? StringFilter(
                  filterString: d.substring(1),
                  type: ComparisonType.endsWithIgnoreCase,
                )
              : StringFilter(
                  filterString: d,
                  type: ComparisonType.equalsIgnoreCase,
                ))
          .toList(),
      keywordFilters: keywords
          .map((k) => StringFilter(
              filterString: k, type: ComparisonType.containsIgnoreCase))
          .toList(),
      hashtagFilters: hashtags
          .map((h) => StringFilter(
              filterString: h, type: ComparisonType.equalsIgnoreCase))
          .toList(),
    );
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is TimelineEntryFilter &&
          runtimeType == other.runtimeType &&
          id == other.id;

  @override
  int get hashCode => id.hashCode;

  Map<String, dynamic> toJson() => {
        'id': id,
        'action': action.name,
        'name': name,
        'enabled': enabled,
        'authorFilters': authorFilters.map((f) => f.toJson()).toList(),
        'domainFilters': domainFilters.map((f) => f.toJson()).toList(),
        'keywordFilters': keywordFilters.map((f) => f.toJson()).toList(),
        'hashtagFilters': hashtagFilters.map((f) => f.toJson()).toList(),
      };

  factory TimelineEntryFilter.fromJson(Map<String, dynamic> json) =>
      TimelineEntryFilter(
        id: json['id'],
        action: TimelineEntryFilterAction.parse(json['action']),
        name: json['name'],
        enabled: json['enabled'] ?? true,
        authorFilters: (json['authorFilters'] as List<dynamic>)
            .map((json) => StringFilter.fromJson(json))
            .toList(),
        domainFilters: (json['domainFilters'] as List<dynamic>)
            .map((json) => StringFilter.fromJson(json))
            .toList(),
        keywordFilters: (json['keywordFilters'] as List<dynamic>)
            .map((json) => StringFilter.fromJson(json))
            .toList(),
        hashtagFilters: (json['hashtagFilters'] as List<dynamic>)
            .map((json) => StringFilter.fromJson(json))
            .toList(),
      );
}
