/*
    This file is part of jellything (https://codeberg.org/metamuffin/jellything)
    which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
    Copyright (C) 2026 metamuffin <metamuffin.org>
*/
use jellycommon::{
    Node, NodeKind, RatingType,
    api::{FilterProperty, NodeFilterSort, SortOrder, SortProperty},
    helpers::SortAnyway,
    user::NodeUserData,
};
use std::sync::Arc;

pub fn filter_and_sort_nodes(
    f: &NodeFilterSort,
    default_sort: (SortProperty, SortOrder),
    nodes: &mut Vec<(Arc<Node>, NodeUserData)>,
) {
    let sort_prop = f.sort_by.unwrap_or(default_sort.0);
    nodes.retain(|(node, _udata)| {
        let mut o = true;
        if let Some(prop) = &f.filter_kind {
            o = false;
            for p in prop {
                o |= match p {
                    // FilterProperty::FederationLocal => node.federated.is_none(),
                    // FilterProperty::FederationRemote => node.federated.is_some(),
                    FilterProperty::KindMovie => node.kind == NodeKind::Movie,
                    FilterProperty::KindVideo => node.kind == NodeKind::Video,
                    FilterProperty::KindShortFormVideo => node.kind == NodeKind::ShortFormVideo,
                    FilterProperty::KindMusic => node.kind == NodeKind::Music,
                    FilterProperty::KindCollection => node.kind == NodeKind::Collection,
                    FilterProperty::KindChannel => node.kind == NodeKind::Channel,
                    FilterProperty::KindShow => node.kind == NodeKind::Show,
                    FilterProperty::KindSeries => node.kind == NodeKind::Series,
                    FilterProperty::KindSeason => node.kind == NodeKind::Season,
                    FilterProperty::KindEpisode => node.kind == NodeKind::Episode,
                    // FilterProperty::Watched => udata.watched == WatchedState::Watched,
                    // FilterProperty::Unwatched => udata.watched == WatchedState::None,
                    // FilterProperty::WatchProgress => {
                    //     matches!(udata.watched, WatchedState::Progress(_))
                    // }
                    _ => false, // TODO
                }
            }
        }
        match sort_prop {
            SortProperty::ReleaseDate => o &= node.release_date.is_some(),
            SortProperty::Duration => o &= node.media.is_some(),
            _ => (),
        }
        o
    });
    match sort_prop {
        SortProperty::Duration => {
            nodes.sort_by_key(|(n, _)| (n.media.as_ref().unwrap().duration * 1000.) as i64)
        }
        SortProperty::ReleaseDate => {
            nodes.sort_by_key(|(n, _)| n.release_date.expect("asserted above"))
        }
        SortProperty::Title => nodes.sort_by(|(a, _), (b, _)| a.title.cmp(&b.title)),
        SortProperty::Index => nodes.sort_by(|(a, _), (b, _)| {
            a.index
                .unwrap_or(usize::MAX)
                .cmp(&b.index.unwrap_or(usize::MAX))
        }),
        SortProperty::RatingRottenTomatoes => nodes.sort_by_cached_key(|(n, _)| {
            SortAnyway(*n.ratings.get(&RatingType::RottenTomatoes).unwrap_or(&0.))
        }),
        SortProperty::RatingMetacritic => nodes.sort_by_cached_key(|(n, _)| {
            SortAnyway(*n.ratings.get(&RatingType::Metacritic).unwrap_or(&0.))
        }),
        SortProperty::RatingImdb => nodes.sort_by_cached_key(|(n, _)| {
            SortAnyway(*n.ratings.get(&RatingType::Imdb).unwrap_or(&0.))
        }),
        SortProperty::RatingTmdb => nodes.sort_by_cached_key(|(n, _)| {
            SortAnyway(*n.ratings.get(&RatingType::Tmdb).unwrap_or(&0.))
        }),
        SortProperty::RatingYoutubeViews => nodes.sort_by_cached_key(|(n, _)| {
            SortAnyway(*n.ratings.get(&RatingType::YoutubeViews).unwrap_or(&0.))
        }),
        SortProperty::RatingYoutubeLikes => nodes.sort_by_cached_key(|(n, _)| {
            SortAnyway(*n.ratings.get(&RatingType::YoutubeLikes).unwrap_or(&0.))
        }),
        SortProperty::RatingYoutubeFollowers => nodes.sort_by_cached_key(|(n, _)| {
            SortAnyway(*n.ratings.get(&RatingType::YoutubeFollowers).unwrap_or(&0.))
        }),
        SortProperty::RatingLikesDivViews => nodes.sort_by_cached_key(|(n, _)| {
            SortAnyway(
                *n.ratings.get(&RatingType::YoutubeLikes).unwrap_or(&0.)
                    / (1. + *n.ratings.get(&RatingType::YoutubeViews).unwrap_or(&0.)),
            )
        }),
        SortProperty::RatingUser => nodes.sort_by_cached_key(|(_, u)| u.rating),
    }

    match f.sort_order.unwrap_or(default_sort.1) {
        SortOrder::Ascending => (),
        SortOrder::Descending => nodes.reverse(),
    }
}
