import 'package:relatica/utils/html_to_edit_text_helper.dart';

import '../models/filters/string_filter.dart';
import '../models/filters/timeline_entry_filter.dart';
import '../models/timeline_entry.dart';

class FilterResult {
  static const show = FilterResult(
    false,
    TimelineEntryFilterAction.warn,
    '',
  );
  final TimelineEntryFilterAction action;
  final bool isFiltered;
  final String trippingFilterName;

  const FilterResult(
    this.isFiltered,
    this.action,
    this.trippingFilterName,
  );

  String toActionString() {
    return isFiltered ? action.name : 'show';
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is FilterResult &&
          runtimeType == other.runtimeType &&
          action == other.action &&
          isFiltered == other.isFiltered &&
          trippingFilterName == other.trippingFilterName;

  @override
  int get hashCode =>
      action.hashCode ^ isFiltered.hashCode ^ trippingFilterName.hashCode;
}

FilterResult runFilters(
  TimelineEntry entry,
  List<TimelineEntryFilter> filters,
) {
  var isFiltered = false;
  var action = TimelineEntryFilterAction.warn;
  var trippingFilterName = '';
  for (final filter in filters.where((f) => f.enabled)) {
    if (filter.isFiltered(entry)) {
      isFiltered = true;
      if (trippingFilterName.isEmpty) {
        trippingFilterName = filter.name;
      }

      if (filter.action == TimelineEntryFilterAction.hide) {
        action = TimelineEntryFilterAction.hide;
        trippingFilterName = filter.name;
        break;
      }
    }
  }

  return FilterResult(isFiltered, action, trippingFilterName);
}

extension StringFilterOps on StringFilter {
  bool isFiltered(String value) {
    switch (type) {
      case ComparisonType.contains:
        return value.contains(filterString);
      case ComparisonType.containsIgnoreCase:
        final lv = value.toLowerCase();
        final lf = filterString.toLowerCase();
        final c = lv.contains(lf);
        return c;
      case ComparisonType.equals:
        return value == filterString;
      case ComparisonType.equalsIgnoreCase:
        return value.toLowerCase() == filterString.toLowerCase();
      case ComparisonType.endsWithIgnoreCase:
        return value.toLowerCase().endsWith(filterString.toLowerCase());
    }
  }
}

extension TimelineEntryFilterOps on TimelineEntryFilter {
  bool isFiltered(TimelineEntry entry) {
    if (authorFilters.isEmpty &&
        domainFilters.isEmpty &&
        hashtagFilters.isEmpty &&
        keywordFilters.isEmpty) {
      return false;
    }

    var authorFiltered = authorFilters.isEmpty ? true : false;
    for (final filter in authorFilters) {
      if (filter.isFiltered(entry.authorId) ||
          filter.isFiltered(entry.parentAuthorId)) {
        authorFiltered = true;
        break;
      }
    }

    var hashtagFiltered = hashtagFilters.isEmpty ? true : false;
    for (final filter in hashtagFilters) {
      for (final tag in entry.tags) {
        if (filter.isFiltered(tag)) {
          hashtagFiltered = true;
          break;
        }
      }
    }

    var domainFiltered = domainFilters.isEmpty ? true : false;
    for (final filter in domainFilters) {
      final domain =
          Uri.tryParse(entry.externalLink)?.host ?? entry.externalLink;
      if (filter.isFiltered(domain)) {
        domainFiltered = true;
        break;
      }
    }

    var contentFiltered = keywordFilters.isEmpty ? true : false;
    final simplifiedBody = keywordFilters.isNotEmpty
        ? htmlToSimpleText(entry.body).toLowerCase()
        : '';
    for (final filter in keywordFilters) {
      if (filter.isFiltered(simplifiedBody)) {
        contentFiltered = true;
        break;
      }
    }

    return authorFiltered &&
        domainFiltered &&
        hashtagFiltered &&
        contentFiltered;
  }
}
