use std::collections::BTreeSet;

use crate::engine::conditions::ResolvedConditionContext;
use crate::engine::metrics::{
    chairman_metric_value, company_metric_value, company_territory_metric_value,
    compare_condition_value,
};
use crate::engine::targets::{
    resolve_chairman_target_ids, resolve_company_target_ids, resolve_player_target_ids,
    resolve_territory_target_ids,
};
use crate::event::conditions::RuntimeConditionComparator;
use crate::event::metrics::{RuntimeChairmanMetric, RuntimeCompanyMetric, RuntimeTrackMetric};
use crate::event::targets::{
    RuntimeChairmanTarget, RuntimeCompanyTarget, RuntimePlayerTarget, RuntimeTerritoryTarget,
};
use crate::state::RuntimeState;

pub(super) fn matching_company_numeric_threshold(
    state: &RuntimeState,
    target: &RuntimeCompanyTarget,
    metric: RuntimeCompanyMetric,
    comparator: RuntimeConditionComparator,
    value: i64,
) -> Result<BTreeSet<u32>, String> {
    Ok(
        resolve_company_target_ids(state, target, &ResolvedConditionContext::default())?
            .into_iter()
            .filter(|company_id| {
                state
                    .companies
                    .iter()
                    .find(|company| company.company_id == *company_id)
                    .is_some_and(|company| {
                        compare_condition_value(
                            company_metric_value(state, company, metric),
                            comparator,
                            value,
                        )
                    })
            })
            .collect(),
    )
}

pub(super) fn matching_company_variable_threshold(
    state: &RuntimeState,
    target: &RuntimeCompanyTarget,
    index: u32,
    comparator: RuntimeConditionComparator,
    value: i64,
) -> Result<BTreeSet<u32>, String> {
    Ok(
        resolve_company_target_ids(state, target, &ResolvedConditionContext::default())?
            .into_iter()
            .filter(|company_id| {
                let actual = state
                    .company_runtime_variables
                    .get(company_id)
                    .and_then(|vars| vars.get(&index))
                    .copied()
                    .unwrap_or(0);
                compare_condition_value(actual, comparator, value)
            })
            .collect(),
    )
}

pub(super) fn matching_player_variable_threshold(
    state: &RuntimeState,
    target: &RuntimePlayerTarget,
    index: u32,
    comparator: RuntimeConditionComparator,
    value: i64,
) -> Result<BTreeSet<u32>, String> {
    Ok(
        resolve_player_target_ids(state, target, &ResolvedConditionContext::default())?
            .into_iter()
            .filter(|player_id| {
                let actual = state
                    .player_runtime_variables
                    .get(player_id)
                    .and_then(|vars| vars.get(&index))
                    .copied()
                    .unwrap_or(0);
                compare_condition_value(actual, comparator, value)
            })
            .collect(),
    )
}

pub(super) fn matching_chairman_numeric_threshold(
    state: &RuntimeState,
    target: &RuntimeChairmanTarget,
    metric: RuntimeChairmanMetric,
    comparator: RuntimeConditionComparator,
    value: i64,
) -> Result<BTreeSet<u32>, String> {
    Ok(
        resolve_chairman_target_ids(state, target, &ResolvedConditionContext::default())?
            .into_iter()
            .filter(|profile_id| {
                state
                    .chairman_profiles
                    .iter()
                    .find(|profile| profile.profile_id == *profile_id)
                    .is_some_and(|profile| {
                        compare_condition_value(
                            chairman_metric_value(profile, metric),
                            comparator,
                            value,
                        )
                    })
            })
            .collect(),
    )
}

pub(super) fn matching_company_territory_numeric_threshold(
    state: &RuntimeState,
    target: &RuntimeCompanyTarget,
    territory: &RuntimeTerritoryTarget,
    metric: RuntimeTrackMetric,
    comparator: RuntimeConditionComparator,
    value: i64,
) -> Result<BTreeSet<u32>, String> {
    let territory_ids = resolve_territory_target_ids(state, territory)?;
    Ok(
        resolve_company_target_ids(state, target, &ResolvedConditionContext::default())?
            .into_iter()
            .filter(|company_id| {
                compare_condition_value(
                    company_territory_metric_value(state, *company_id, &territory_ids, metric),
                    comparator,
                    value,
                )
            })
            .collect(),
    )
}
