//
//  ContentFilters.swift
//  damus
//
//  Created by Daniel D’Aquino on 2023-09-18.
//

import Foundation

/// Timeline source determines whether to show content from follows or favorites
enum TimelineSource: CustomStringConvertible {
    case follows
    case favorites

    var description: String {
        switch self {
        case .follows:
            return NSLocalizedString("Follows", comment: "Show Notes from your following")
        case .favorites:
            return NSLocalizedString("Favorites", comment: "Show Notes from your favorites")
        }
    }
}

/// Simple filter to determine whether to show posts or all posts and replies.
enum FilterState : Int {
    case posts = 0
    case posts_and_replies = 1
    case conversations = 2
    case follow_list = 3
    case live = 4
    case live_chat = 5

    func filter(ev: NostrEvent) -> Bool {
        switch self {
        case .posts:
            return ev.known_kind == .boost || ev.known_kind == .highlight || !ev.is_reply()
        case .posts_and_replies:
            return true
        case .conversations:
            return true
        case .follow_list:
            return ev.known_kind == .follow_list
        case .live:
            return ev.known_kind == .live
        case .live_chat:
            return ev.known_kind == .live_chat
        }
    }
}

/// Simple filter to determine whether to show posts with #nsfw tags
func nsfw_tag_filter(ev: NostrEvent) -> Bool {
    return ev.referenced_hashtags.first(where: { t in t.hashtag.caseInsensitiveCompare("nsfw") == .orderedSame }) == nil
}

/// Filter to hide posts with too many hashtags (spam detection)
/// Checks both the event's "t" tags and hashtags in content text.
/// If either exceeds the threshold, the post is filtered.
func hashtag_spam_filter(ev: NostrEvent, max_hashtags: Int) -> Bool {
    // Check "t" tags count
    var tag_count = 0
    for _ in ev.referenced_hashtags {
        tag_count += 1
        if tag_count > max_hashtags {
            return false
        }
    }

    return true
}

@MainActor
func get_repost_of_muted_user_filter(damus_state: DamusState) -> ((_ ev: NostrEvent) -> Bool) {
    return { ev in
        guard ev.known_kind == .boost else { return true }
        // This needs to use cached because it can be way too slow otherwise
        guard let inner_ev = ev.get_cached_inner_event(cache: damus_state.events) else { return true }
        return should_show_event(state: damus_state, ev: inner_ev)
    }
}

func timestamp_filter(ev: NostrEvent) -> Bool {
    // Allow notes that are created no more than 3 seconds in the future
    // to account for natural clock skew between sender and receiver.
    ev.age >= -3
}

/// Generic filter with various tweakable settings
struct ContentFilters {
    var filters: [(NostrEvent) -> Bool]

    func filter(ev: NostrEvent) -> Bool {
        for filter in filters {
            if !filter(ev) {
                return false
            }
        }

        return true
    }
}

extension ContentFilters {
    @MainActor
    static func default_filters(damus_state: DamusState) -> ContentFilters {
        return ContentFilters(filters: ContentFilters.defaults(damus_state: damus_state))
    }

    @MainActor
    static func defaults(damus_state: DamusState) -> [(NostrEvent) -> Bool] {
        var filters = Array<(NostrEvent) -> Bool>()
        if damus_state.settings.hide_nsfw_tagged_content {
            filters.append(nsfw_tag_filter)
        }
        if damus_state.settings.hide_hashtag_spam {
            let max_hashtags = damus_state.settings.max_hashtags
            filters.append({ ev in hashtag_spam_filter(ev: ev, max_hashtags: max_hashtags) })
        }
        filters.append(get_repost_of_muted_user_filter(damus_state: damus_state))
        filters.append(timestamp_filter)
        return filters
    }
}
