use std::collections::BTreeSet;

use crate::engine::conditions::ResolvedConditionContext;
use crate::engine::targets::{resolve_chairman_target_ids, resolve_player_target_ids};
use crate::event::targets::{RuntimeChairmanTarget, RuntimePlayerTarget};
use crate::state::RuntimeState;

pub(super) fn apply_set_player_cash(
    state: &mut RuntimeState,
    target: &RuntimePlayerTarget,
    value: i64,
    condition_context: &ResolvedConditionContext,
    mutated_player_ids: &mut BTreeSet<u32>,
) -> Result<(), String> {
    let player_ids = resolve_player_target_ids(state, target, condition_context)?;
    for player_id in player_ids {
        let player = state
            .players
            .iter_mut()
            .find(|player| player.player_id == player_id)
            .ok_or_else(|| format!("missing player_id {player_id} while applying cash effect"))?;
        player.current_cash = value;
        mutated_player_ids.insert(player_id);
    }
    Ok(())
}

pub(super) fn apply_set_chairman_cash(
    state: &mut RuntimeState,
    target: &RuntimeChairmanTarget,
    value: i64,
    condition_context: &ResolvedConditionContext,
) -> Result<(), String> {
    let profile_ids = resolve_chairman_target_ids(state, target, condition_context)?;
    for profile_id in profile_ids {
        let chairman = state
            .chairman_profiles
            .iter_mut()
            .find(|profile| profile.profile_id == profile_id)
            .ok_or_else(|| {
                format!("missing chairman profile_id {profile_id} while applying cash effect")
            })?;
        let preserved_threshold_adjusted_holdings_component = chairman
            .purchasing_power_total
            .saturating_sub(chairman.current_cash)
            .max(0);
        chairman.current_cash = value;
        chairman.purchasing_power_total = chairman
            .current_cash
            .saturating_add(preserved_threshold_adjusted_holdings_component);
    }
    Ok(())
}

pub(super) fn apply_deactivate_player(
    state: &mut RuntimeState,
    target: &RuntimePlayerTarget,
    condition_context: &ResolvedConditionContext,
    mutated_player_ids: &mut BTreeSet<u32>,
) -> Result<(), String> {
    let player_ids = resolve_player_target_ids(state, target, condition_context)?;
    for player_id in player_ids {
        let player = state
            .players
            .iter_mut()
            .find(|player| player.player_id == player_id)
            .ok_or_else(|| {
                format!("missing player_id {player_id} while applying deactivate effect")
            })?;
        player.active = false;
        mutated_player_ids.insert(player_id);
        if state.selected_player_id == Some(player_id) {
            state.selected_player_id = None;
        }
    }
    Ok(())
}

pub(super) fn apply_deactivate_chairman(
    state: &mut RuntimeState,
    target: &RuntimeChairmanTarget,
    condition_context: &ResolvedConditionContext,
    mutated_company_ids: &mut BTreeSet<u32>,
) -> Result<(), String> {
    let profile_ids = resolve_chairman_target_ids(state, target, condition_context)?;
    for profile_id in profile_ids.iter().copied() {
        let linked_company_id = state
            .chairman_profiles
            .iter()
            .find(|profile| profile.profile_id == profile_id)
            .and_then(|profile| profile.linked_company_id);
        let chairman = state
            .chairman_profiles
            .iter_mut()
            .find(|profile| profile.profile_id == profile_id)
            .ok_or_else(|| {
                format!("missing chairman profile_id {profile_id} while applying deactivate effect")
            })?;
        chairman.active = false;
        chairman.linked_company_id = None;
        if state.selected_chairman_profile_id == Some(profile_id) {
            state.selected_chairman_profile_id = None;
        }
        if let Some(linked_company_id) = linked_company_id {
            if let Some(company) = state
                .companies
                .iter_mut()
                .find(|company| company.company_id == linked_company_id)
            {
                company.linked_chairman_profile_id = None;
                mutated_company_ids.insert(linked_company_id);
            }
            for other in &mut state.chairman_profiles {
                if other.profile_id != profile_id
                    && other.linked_company_id == Some(linked_company_id)
                {
                    other.linked_company_id = None;
                }
            }
        }
    }
    Ok(())
}

pub(super) fn apply_set_player_variable(
    state: &mut RuntimeState,
    target: &RuntimePlayerTarget,
    index: u32,
    value: i64,
    condition_context: &ResolvedConditionContext,
) -> Result<(), String> {
    let player_ids = resolve_player_target_ids(state, target, condition_context)?;
    for player_id in player_ids {
        state
            .player_runtime_variables
            .entry(player_id)
            .or_default()
            .insert(index, value);
    }
    Ok(())
}
