use super::record::smp_runtime_record_template_to_runtime;
use super::targets::{
    import_chairman_target, import_company_target, import_player_target, import_territory_target,
};
use crate::documents::RuntimeImportContext;
use crate::event::effects::RuntimeEffect;

pub(crate) fn smp_runtime_effects_to_runtime_effects(
    effects: &[RuntimeEffect],
    runtime_context: &RuntimeImportContext,
    allow_condition_true_company: bool,
    allow_condition_true_player: bool,
) -> Result<Vec<RuntimeEffect>, String> {
    effects
        .iter()
        .map(|effect| {
            smp_runtime_effect_to_runtime_effect(
                effect,
                runtime_context,
                allow_condition_true_company,
                allow_condition_true_player,
            )
        })
        .collect()
}

pub(crate) fn smp_runtime_effect_to_runtime_effect(
    effect: &RuntimeEffect,
    runtime_context: &RuntimeImportContext,
    allow_condition_true_company: bool,
    allow_condition_true_player: bool,
) -> Result<RuntimeEffect, String> {
    match effect {
        RuntimeEffect::SetWorldFlag { key, value } => Ok(RuntimeEffect::SetWorldFlag {
            key: key.clone(),
            value: *value,
        }),
        RuntimeEffect::SetWorldVariable { index, value } => Ok(RuntimeEffect::SetWorldVariable {
            index: *index,
            value: *value,
        }),
        RuntimeEffect::SetLimitedTrackBuildingAmount { value } => {
            Ok(RuntimeEffect::SetLimitedTrackBuildingAmount { value: *value })
        }
        RuntimeEffect::SetEconomicStatusCode { value } => {
            Ok(RuntimeEffect::SetEconomicStatusCode { value: *value })
        }
        RuntimeEffect::SetCompanyVariable {
            target,
            index,
            value,
        } => Ok(RuntimeEffect::SetCompanyVariable {
            target: import_company_target(target, runtime_context, allow_condition_true_company)?,
            index: *index,
            value: *value,
        }),
        RuntimeEffect::SetCompanyCash { target, value } => Ok(RuntimeEffect::SetCompanyCash {
            target: import_company_target(target, runtime_context, allow_condition_true_company)?,
            value: *value,
        }),
        RuntimeEffect::SetPlayerVariable {
            target,
            index,
            value,
        } => Ok(RuntimeEffect::SetPlayerVariable {
            target: import_player_target(target, runtime_context, allow_condition_true_player)?,
            index: *index,
            value: *value,
        }),
        RuntimeEffect::SetPlayerCash { target, value } => Ok(RuntimeEffect::SetPlayerCash {
            target: import_player_target(target, runtime_context, allow_condition_true_player)?,
            value: *value,
        }),
        RuntimeEffect::SetTerritoryVariable {
            target,
            index,
            value,
        } => Ok(RuntimeEffect::SetTerritoryVariable {
            target: import_territory_target(target, runtime_context)?,
            index: *index,
            value: *value,
        }),
        RuntimeEffect::SetChairmanCash { target, value } => Ok(RuntimeEffect::SetChairmanCash {
            target: import_chairman_target(target, runtime_context)?,
            value: *value,
        }),
        RuntimeEffect::DeactivatePlayer { target } => Ok(RuntimeEffect::DeactivatePlayer {
            target: import_player_target(target, runtime_context, allow_condition_true_player)?,
        }),
        RuntimeEffect::DeactivateChairman { target } => Ok(RuntimeEffect::DeactivateChairman {
            target: import_chairman_target(target, runtime_context)?,
        }),
        RuntimeEffect::SetCompanyTerritoryAccess {
            target,
            territory,
            value,
        } => Ok(RuntimeEffect::SetCompanyTerritoryAccess {
            target: import_company_target(target, runtime_context, allow_condition_true_company)?,
            territory: import_territory_target(territory, runtime_context)?,
            value: *value,
        }),
        RuntimeEffect::ConfiscateCompanyAssets { target } => {
            if !runtime_context.has_train_context {
                Err("packed effect requires runtime train context".to_string())
            } else {
                Ok(RuntimeEffect::ConfiscateCompanyAssets {
                    target: import_company_target(
                        target,
                        runtime_context,
                        allow_condition_true_company,
                    )?,
                })
            }
        }
        RuntimeEffect::DeactivateCompany { target } => Ok(RuntimeEffect::DeactivateCompany {
            target: import_company_target(target, runtime_context, allow_condition_true_company)?,
        }),
        RuntimeEffect::SetCompanyTrackLayingCapacity { target, value } => {
            Ok(RuntimeEffect::SetCompanyTrackLayingCapacity {
                target: import_company_target(
                    target,
                    runtime_context,
                    allow_condition_true_company,
                )?,
                value: *value,
            })
        }
        RuntimeEffect::SetCompanyGovernanceScalar {
            target,
            metric,
            value,
        } => Ok(RuntimeEffect::SetCompanyGovernanceScalar {
            target: import_company_target(target, runtime_context, allow_condition_true_company)?,
            metric: *metric,
            value: *value,
        }),
        RuntimeEffect::RetireTrains {
            company_target,
            territory_target,
            locomotive_name,
        } => {
            if !runtime_context.has_train_context {
                Err("packed effect requires runtime train context".to_string())
            } else if territory_target.is_some() && !runtime_context.has_train_territory_context {
                Err("packed train effect requires runtime train territory context".to_string())
            } else {
                let imported_company_target = company_target
                    .as_ref()
                    .map(|target| {
                        import_company_target(target, runtime_context, allow_condition_true_company)
                    })
                    .transpose()?;
                let imported_territory_target = territory_target
                    .as_ref()
                    .map(|target| import_territory_target(target, runtime_context))
                    .transpose()?;
                Ok(RuntimeEffect::RetireTrains {
                    company_target: imported_company_target,
                    territory_target: imported_territory_target,
                    locomotive_name: locomotive_name.clone(),
                })
            }
        }
        RuntimeEffect::AdjustCompanyCash { target, delta } => {
            Ok(RuntimeEffect::AdjustCompanyCash {
                target: import_company_target(
                    target,
                    runtime_context,
                    allow_condition_true_company,
                )?,
                delta: *delta,
            })
        }
        RuntimeEffect::AdjustCompanyDebt { target, delta } => {
            Ok(RuntimeEffect::AdjustCompanyDebt {
                target: import_company_target(
                    target,
                    runtime_context,
                    allow_condition_true_company,
                )?,
                delta: *delta,
            })
        }
        RuntimeEffect::SetCandidateAvailability { name, value } => {
            Ok(RuntimeEffect::SetCandidateAvailability {
                name: name.clone(),
                value: *value,
            })
        }
        RuntimeEffect::SetNamedLocomotiveAvailability { name, value } => {
            Ok(RuntimeEffect::SetNamedLocomotiveAvailability {
                name: name.clone(),
                value: *value,
            })
        }
        RuntimeEffect::SetNamedLocomotiveAvailabilityValue { name, value } => {
            Ok(RuntimeEffect::SetNamedLocomotiveAvailabilityValue {
                name: name.clone(),
                value: *value,
            })
        }
        RuntimeEffect::SetNamedLocomotiveCost { name, value } => {
            Ok(RuntimeEffect::SetNamedLocomotiveCost {
                name: name.clone(),
                value: *value,
            })
        }
        RuntimeEffect::SetCargoPriceOverride { target, value } => {
            Ok(RuntimeEffect::SetCargoPriceOverride {
                target: target.clone(),
                value: *value,
            })
        }
        RuntimeEffect::SetCargoProductionOverride { target, value } => {
            Ok(RuntimeEffect::SetCargoProductionOverride {
                target: target.clone(),
                value: *value,
            })
        }
        RuntimeEffect::SetWorldScalarOverride { key, value } => {
            Ok(RuntimeEffect::SetWorldScalarOverride {
                key: key.clone(),
                value: *value,
            })
        }
        RuntimeEffect::SetCargoProductionSlot { slot, value } => {
            Ok(RuntimeEffect::SetCargoProductionSlot {
                slot: *slot,
                value: *value,
            })
        }
        RuntimeEffect::SetTerritoryAccessCost { value } => {
            Ok(RuntimeEffect::SetTerritoryAccessCost { value: *value })
        }
        RuntimeEffect::SetSpecialCondition { label, value } => {
            Ok(RuntimeEffect::SetSpecialCondition {
                label: label.clone(),
                value: *value,
            })
        }
        RuntimeEffect::AppendEventRecord { record } => Ok(RuntimeEffect::AppendEventRecord {
            record: Box::new(smp_runtime_record_template_to_runtime(
                record,
                runtime_context,
                allow_condition_true_company,
                allow_condition_true_player,
            )?),
        }),
        RuntimeEffect::ActivateEventRecord { record_id } => {
            Ok(RuntimeEffect::ActivateEventRecord {
                record_id: *record_id,
            })
        }
        RuntimeEffect::DeactivateEventRecord { record_id } => {
            Ok(RuntimeEffect::DeactivateEventRecord {
                record_id: *record_id,
            })
        }
        RuntimeEffect::RemoveEventRecord { record_id } => Ok(RuntimeEffect::RemoveEventRecord {
            record_id: *record_id,
        }),
    }
}
