use std::collections::BTreeSet;

use crate::event::effects::RuntimeEffect;
use crate::event::targets::{RuntimeCargoPriceTarget, RuntimeCargoProductionTarget};

use super::{
    validate_chairman_target, validate_company_governance_scalar_metric, validate_company_target,
    validate_event_record_template, validate_player_target, validate_territory_target,
};

pub(crate) fn validate_runtime_effect(
    effect: &RuntimeEffect,
    valid_company_ids: &BTreeSet<u32>,
    valid_player_ids: &BTreeSet<u32>,
    valid_chairman_profile_ids: &BTreeSet<u32>,
    valid_territory_ids: &BTreeSet<u32>,
) -> Result<(), String> {
    match effect {
        RuntimeEffect::SetWorldFlag { key, .. } => {
            if key.trim().is_empty() {
                return Err("key must not be empty".to_string());
            }
        }
        RuntimeEffect::SetWorldVariable { index, .. } => {
            if !(1..=4).contains(index) {
                return Err(format!(
                    "world runtime variable index {index} must be in 1..=4"
                ));
            }
        }
        RuntimeEffect::SetWorldScalarOverride { key, .. } => {
            if key.trim().is_empty() {
                return Err("key must not be empty".to_string());
            }
        }
        RuntimeEffect::SetLimitedTrackBuildingAmount { .. }
        | RuntimeEffect::SetEconomicStatusCode { .. } => {}
        RuntimeEffect::SetCompanyVariable { target, index, .. } => {
            validate_company_target(target, valid_company_ids)?;
            if !(1..=4).contains(index) {
                return Err(format!("runtime variable index {index} must be in 1..=4"));
            }
        }
        RuntimeEffect::SetCompanyCash { target, .. }
        | RuntimeEffect::ConfiscateCompanyAssets { target }
        | RuntimeEffect::DeactivateCompany { target }
        | RuntimeEffect::SetCompanyTrackLayingCapacity { target, .. }
        | RuntimeEffect::AdjustCompanyCash { target, .. }
        | RuntimeEffect::AdjustCompanyDebt { target, .. } => {
            validate_company_target(target, valid_company_ids)?;
        }
        RuntimeEffect::SetCompanyGovernanceScalar { target, metric, .. } => {
            validate_company_target(target, valid_company_ids)?;
            validate_company_governance_scalar_metric(*metric)?;
        }
        RuntimeEffect::SetCompanyTerritoryAccess {
            target, territory, ..
        } => {
            validate_company_target(target, valid_company_ids)?;
            validate_territory_target(territory, valid_territory_ids)?;
        }
        RuntimeEffect::SetPlayerVariable { target, index, .. } => {
            validate_player_target(target, valid_player_ids)?;
            if !(1..=4).contains(index) {
                return Err(format!("runtime variable index {index} must be in 1..=4"));
            }
        }
        RuntimeEffect::SetPlayerCash { target, .. }
        | RuntimeEffect::DeactivatePlayer { target } => {
            validate_player_target(target, valid_player_ids)?;
        }
        RuntimeEffect::SetChairmanCash { target, .. }
        | RuntimeEffect::DeactivateChairman { target } => {
            validate_chairman_target(target, valid_chairman_profile_ids)?;
        }
        RuntimeEffect::RetireTrains {
            company_target,
            territory_target,
            locomotive_name,
        } => {
            if let Some(company_target) = company_target {
                validate_company_target(company_target, valid_company_ids)?;
            }
            if let Some(territory_target) = territory_target {
                validate_territory_target(territory_target, valid_territory_ids)?;
            }
            if company_target.is_none() && territory_target.is_none() && locomotive_name.is_none() {
                return Err(
                    "retire_trains requires at least one company_target, territory_target, or locomotive_name filter"
                        .to_string(),
                );
            }
            if locomotive_name
                .as_deref()
                .is_some_and(|value| value.trim().is_empty())
            {
                return Err("locomotive_name must not be empty".to_string());
            }
        }
        RuntimeEffect::SetCandidateAvailability { name, .. }
        | RuntimeEffect::SetNamedLocomotiveAvailability { name, .. }
        | RuntimeEffect::SetNamedLocomotiveAvailabilityValue { name, .. }
        | RuntimeEffect::SetNamedLocomotiveCost { name, .. } => {
            if name.trim().is_empty() {
                return Err("name must not be empty".to_string());
            }
        }
        RuntimeEffect::SetCargoPriceOverride { target, .. } => match target {
            RuntimeCargoPriceTarget::All => {}
            RuntimeCargoPriceTarget::Named { name } => {
                if name.trim().is_empty() {
                    return Err("name must not be empty".to_string());
                }
            }
        },
        RuntimeEffect::SetCargoProductionOverride { target, .. } => match target {
            RuntimeCargoProductionTarget::All
            | RuntimeCargoProductionTarget::Factory
            | RuntimeCargoProductionTarget::FarmMine => {}
            RuntimeCargoProductionTarget::Named { name } => {
                if name.trim().is_empty() {
                    return Err("name must not be empty".to_string());
                }
            }
        },
        RuntimeEffect::SetCargoProductionSlot { slot, .. } => {
            if !(1..=11).contains(slot) {
                return Err("slot must be in 1..=11".to_string());
            }
        }
        RuntimeEffect::SetTerritoryVariable { target, index, .. } => {
            validate_territory_target(target, valid_territory_ids)?;
            if !(1..=4).contains(index) {
                return Err(format!("runtime variable index {index} must be in 1..=4"));
            }
        }
        RuntimeEffect::SetTerritoryAccessCost { .. } => {}
        RuntimeEffect::SetSpecialCondition { label, .. } => {
            if label.trim().is_empty() {
                return Err("label must not be empty".to_string());
            }
        }
        RuntimeEffect::AppendEventRecord { record } => {
            validate_event_record_template(
                record,
                valid_company_ids,
                valid_player_ids,
                valid_chairman_profile_ids,
                valid_territory_ids,
            )?;
        }
        RuntimeEffect::ActivateEventRecord { .. }
        | RuntimeEffect::DeactivateEventRecord { .. }
        | RuntimeEffect::RemoveEventRecord { .. } => {}
    }

    Ok(())
}
