use std::collections::BTreeSet;

use crate::engine::conditions::ResolvedConditionContext;
use crate::engine::effects::{AppliedEffectsSummary, EventGraphMutation};
use crate::event::effects::RuntimeEffect;
use crate::state::RuntimeState;

use super::{catalogs, company, event_graph, players, territories, trains, world};

pub(in crate::engine) fn apply_runtime_effects(
    state: &mut RuntimeState,
    effects: &[RuntimeEffect],
    condition_context: &ResolvedConditionContext,
    mutated_company_ids: &mut BTreeSet<u32>,
    mutated_player_ids: &mut BTreeSet<u32>,
    staged_event_graph_mutations: &mut Vec<EventGraphMutation>,
) -> Result<AppliedEffectsSummary, String> {
    let mut summary = AppliedEffectsSummary::default();

    for effect in effects {
        match effect {
            RuntimeEffect::SetWorldFlag { key, value } => {
                world::apply_set_world_flag(state, key, *value);
            }
            RuntimeEffect::SetWorldScalarOverride { key, value } => {
                world::apply_set_world_scalar_override(state, key, *value);
            }
            RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
                world::apply_set_limited_track_building_amount(state, *value);
            }
            RuntimeEffect::SetEconomicStatusCode { value } => {
                world::apply_set_economic_status_code(state, *value);
            }
            RuntimeEffect::SetWorldVariable { index, value } => {
                world::apply_set_world_variable(state, *index, *value);
            }
            RuntimeEffect::SetSpecialCondition { label, value } => {
                world::apply_set_special_condition(state, label, *value);
            }
            RuntimeEffect::SetCompanyCash { target, value } => {
                company::apply_set_company_cash(
                    state,
                    target,
                    *value,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::SetCompanyGovernanceScalar {
                target,
                metric,
                value,
            } => {
                company::apply_set_company_governance_scalar(
                    state,
                    target,
                    *metric,
                    *value,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::SetCompanyTerritoryAccess {
                target,
                territory,
                value,
            } => {
                company::apply_set_company_territory_access(
                    state,
                    target,
                    territory,
                    *value,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::ConfiscateCompanyAssets { target } => {
                company::apply_confiscate_company_assets(
                    state,
                    target,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::DeactivateCompany { target } => {
                company::apply_deactivate_company(
                    state,
                    target,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::SetCompanyTrackLayingCapacity { target, value } => {
                company::apply_set_company_track_laying_capacity(
                    state,
                    target,
                    *value,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::AdjustCompanyCash { target, delta } => {
                company::apply_adjust_company_cash(
                    state,
                    target,
                    *delta,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::AdjustCompanyDebt { target, delta } => {
                company::apply_adjust_company_debt(
                    state,
                    target,
                    *delta,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::SetCompanyVariable {
                target,
                index,
                value,
            } => {
                company::apply_set_company_variable(
                    state,
                    target,
                    *index,
                    *value,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::SetPlayerCash { target, value } => {
                players::apply_set_player_cash(
                    state,
                    target,
                    *value,
                    condition_context,
                    mutated_player_ids,
                )?;
            }
            RuntimeEffect::SetChairmanCash { target, value } => {
                players::apply_set_chairman_cash(state, target, *value, condition_context)?;
            }
            RuntimeEffect::DeactivatePlayer { target } => {
                players::apply_deactivate_player(
                    state,
                    target,
                    condition_context,
                    mutated_player_ids,
                )?;
            }
            RuntimeEffect::DeactivateChairman { target } => {
                players::apply_deactivate_chairman(
                    state,
                    target,
                    condition_context,
                    mutated_company_ids,
                )?;
            }
            RuntimeEffect::SetPlayerVariable {
                target,
                index,
                value,
            } => {
                players::apply_set_player_variable(
                    state,
                    target,
                    *index,
                    *value,
                    condition_context,
                )?;
            }
            RuntimeEffect::SetTerritoryVariable {
                target,
                index,
                value,
            } => {
                territories::apply_set_territory_variable(state, target, *index, *value)?;
            }
            RuntimeEffect::SetTerritoryAccessCost { value } => {
                territories::apply_set_territory_access_cost(state, *value);
            }
            RuntimeEffect::SetCandidateAvailability { name, value } => {
                catalogs::apply_set_candidate_availability(state, name, *value);
            }
            RuntimeEffect::SetNamedLocomotiveAvailability { name, value } => {
                catalogs::apply_set_named_locomotive_availability(state, name, *value);
            }
            RuntimeEffect::SetNamedLocomotiveAvailabilityValue { name, value } => {
                catalogs::apply_set_named_locomotive_availability_value(state, name, *value);
            }
            RuntimeEffect::SetNamedLocomotiveCost { name, value } => {
                catalogs::apply_set_named_locomotive_cost(state, name, *value);
            }
            RuntimeEffect::SetCargoPriceOverride { target, value } => {
                catalogs::apply_set_cargo_price_override(state, target, *value);
            }
            RuntimeEffect::SetCargoProductionOverride { target, value } => {
                catalogs::apply_set_cargo_production_override(state, target, *value);
            }
            RuntimeEffect::SetCargoProductionSlot { slot, value } => {
                catalogs::apply_set_cargo_production_slot(state, *slot, *value);
            }
            RuntimeEffect::RetireTrains {
                company_target,
                territory_target,
                locomotive_name,
            } => {
                trains::apply_retire_trains(
                    state,
                    company_target.as_ref(),
                    territory_target.as_ref(),
                    locomotive_name.as_deref(),
                    condition_context,
                )?;
            }
            RuntimeEffect::AppendEventRecord { record } => {
                event_graph::apply_append_event_record(
                    &mut summary,
                    staged_event_graph_mutations,
                    record,
                );
            }
            RuntimeEffect::ActivateEventRecord { record_id } => {
                event_graph::apply_activate_event_record(
                    &mut summary,
                    staged_event_graph_mutations,
                    *record_id,
                );
            }
            RuntimeEffect::DeactivateEventRecord { record_id } => {
                event_graph::apply_deactivate_event_record(
                    &mut summary,
                    staged_event_graph_mutations,
                    *record_id,
                );
            }
            RuntimeEffect::RemoveEventRecord { record_id } => {
                event_graph::apply_remove_event_record(
                    &mut summary,
                    staged_event_graph_mutations,
                    *record_id,
                );
            }
        }

        summary.applied_effect_count += 1;
    }

    Ok(summary)
}
