use crate::inspect::smp::events::*;
use crate::inspect::smp::*;

pub(super) fn decode_actor_effect(
    row: &SmpLoadedPackedEventGroupedEffectRowSummary,
    compact_control: &SmpLoadedPackedEventCompactControlSummary,
    descriptor_metadata: RealGroupedEffectDescriptorMetadata,
    target_subject: Option<RealGroupedTargetSubject>,
    target_scope_ordinal: u8,
) -> Option<RuntimeEffect> {
    decode_company_governance_effect(row, descriptor_metadata, target_scope_ordinal)
        .or_else(|| {
            decode_cash_effect(
                row,
                descriptor_metadata,
                target_subject,
                target_scope_ordinal,
            )
        })
        .or_else(|| {
            decode_company_territory_access_effect(
                row,
                compact_control,
                descriptor_metadata,
                target_scope_ordinal,
            )
        })
        .or_else(|| decode_confiscate_effect(row, descriptor_metadata, target_scope_ordinal))
        .or_else(|| {
            decode_deactivate_effect(
                row,
                descriptor_metadata,
                target_subject,
                target_scope_ordinal,
            )
        })
        .or_else(|| {
            decode_track_laying_capacity_effect(row, descriptor_metadata, target_scope_ordinal)
        })
}

fn decode_company_governance_effect(
    row: &SmpLoadedPackedEventGroupedEffectRowSummary,
    descriptor_metadata: RealGroupedEffectDescriptorMetadata,
    target_scope_ordinal: u8,
) -> Option<RuntimeEffect> {
    if descriptor_metadata.executable_in_runtime
        && descriptor_metadata.parameter_family == "company_governance_scalar"
        && row.row_shape == "scalar_assignment"
    {
        let target = real_grouped_company_target(target_scope_ordinal)?;
        let metric = real_grouped_company_governance_metric(descriptor_metadata)?;
        return Some(RuntimeEffect::SetCompanyGovernanceScalar {
            target,
            metric,
            value: i64::from(row.raw_scalar_value),
        });
    }
    None
}

fn decode_cash_effect(
    row: &SmpLoadedPackedEventGroupedEffectRowSummary,
    descriptor_metadata: RealGroupedEffectDescriptorMetadata,
    target_subject: Option<RealGroupedTargetSubject>,
    target_scope_ordinal: u8,
) -> Option<RuntimeEffect> {
    if descriptor_metadata.executable_in_runtime
        && descriptor_metadata.descriptor_id == 1
        && row.opcode == 8
        && row.row_shape == "multivalue_scalar"
    {
        return match target_subject {
            Some(RealGroupedTargetSubject::Chairman) => Some(RuntimeEffect::SetChairmanCash {
                target: real_grouped_chairman_target(target_scope_ordinal)?,
                value: i64::from(row.raw_scalar_value),
            }),
            _ => Some(RuntimeEffect::SetPlayerCash {
                target: real_grouped_player_target(target_scope_ordinal)?,
                value: i64::from(row.raw_scalar_value),
            }),
        };
    }

    if descriptor_metadata.executable_in_runtime
        && descriptor_metadata.descriptor_id == 2
        && row.opcode == 8
        && row.row_shape == "multivalue_scalar"
    {
        let target = real_grouped_company_target(target_scope_ordinal)?;
        return Some(RuntimeEffect::SetCompanyCash {
            target,
            value: i64::from(row.raw_scalar_value),
        });
    }

    None
}

fn decode_company_territory_access_effect(
    row: &SmpLoadedPackedEventGroupedEffectRowSummary,
    compact_control: &SmpLoadedPackedEventCompactControlSummary,
    descriptor_metadata: RealGroupedEffectDescriptorMetadata,
    target_scope_ordinal: u8,
) -> Option<RuntimeEffect> {
    if descriptor_metadata.executable_in_runtime
        && descriptor_metadata.descriptor_id == 3
        && row.row_shape == "bool_toggle"
        && row.raw_scalar_value != 0
    {
        let target = real_grouped_company_target(target_scope_ordinal)?;
        let territory = compact_control
            .grouped_territory_selectors_0x80f
            .get(row.group_index)
            .copied()
            .filter(|selector| *selector >= 0)
            .map(|selector| RuntimeTerritoryTarget::Ids {
                ids: vec![selector as u32],
            })?;
        return Some(RuntimeEffect::SetCompanyTerritoryAccess {
            target,
            territory,
            value: true,
        });
    }
    None
}

fn decode_confiscate_effect(
    row: &SmpLoadedPackedEventGroupedEffectRowSummary,
    descriptor_metadata: RealGroupedEffectDescriptorMetadata,
    target_scope_ordinal: u8,
) -> Option<RuntimeEffect> {
    if descriptor_metadata.executable_in_runtime
        && descriptor_metadata.descriptor_id == 9
        && row.row_shape == "bool_toggle"
        && row.raw_scalar_value != 0
    {
        let target = real_grouped_company_target(target_scope_ordinal)?;
        return Some(RuntimeEffect::ConfiscateCompanyAssets { target });
    }
    None
}

fn decode_deactivate_effect(
    row: &SmpLoadedPackedEventGroupedEffectRowSummary,
    descriptor_metadata: RealGroupedEffectDescriptorMetadata,
    target_subject: Option<RealGroupedTargetSubject>,
    target_scope_ordinal: u8,
) -> Option<RuntimeEffect> {
    if descriptor_metadata.executable_in_runtime
        && descriptor_metadata.descriptor_id == 13
        && row.row_shape == "bool_toggle"
        && row.raw_scalar_value != 0
    {
        let target = real_grouped_company_target(target_scope_ordinal)?;
        return Some(RuntimeEffect::DeactivateCompany { target });
    }

    if descriptor_metadata.executable_in_runtime
        && descriptor_metadata.descriptor_id == 14
        && row.row_shape == "bool_toggle"
        && row.raw_scalar_value != 0
    {
        return match target_subject {
            Some(RealGroupedTargetSubject::Chairman) => Some(RuntimeEffect::DeactivateChairman {
                target: real_grouped_chairman_target(target_scope_ordinal)?,
            }),
            _ => Some(RuntimeEffect::DeactivatePlayer {
                target: real_grouped_player_target(target_scope_ordinal)?,
            }),
        };
    }

    None
}

fn decode_track_laying_capacity_effect(
    row: &SmpLoadedPackedEventGroupedEffectRowSummary,
    descriptor_metadata: RealGroupedEffectDescriptorMetadata,
    target_scope_ordinal: u8,
) -> Option<RuntimeEffect> {
    if descriptor_metadata.executable_in_runtime
        && descriptor_metadata.descriptor_id == 16
        && row.row_shape == "scalar_assignment"
        && row.raw_scalar_value >= 0
    {
        let target = real_grouped_company_target(target_scope_ordinal)?;
        return Some(RuntimeEffect::SetCompanyTrackLayingCapacity {
            target,
            value: Some(row.raw_scalar_value as u32),
        });
    }
    None
}
