use cryp::{Stat, Colours};

#[derive(Debug,Copy,Clone,Serialize,Deserialize,PartialEq,PartialOrd,Ord,Eq)]
pub enum Spec {
    Speed,
    RedSpeedI,
    BlueSpeedI,
    GreenSpeedI,
    GRSpeedI,
    GBSpeedI,
    RBSpeedI,
    // Pure redShield has to come first as it applies the base amount
    // that is multiplied
    Hp,
    LifeI,
    RedShieldI,
    BlueShieldI,
    LRSI,
    LBSI,
    RBSI,

    Damage,
    RedDamageI,
    GreenDamageI,
    BlueDamageI,
    GRDI,
    GBDI,
    RBDI,
}

pub trait IntPct {
    fn pct(self, pct: u64) -> u64;
}

impl IntPct for u64 {
    fn pct(self, pct: u64) -> u64 {
        self * pct / 100
    }
}

impl Spec {
    pub fn affects(&self) -> Vec<Stat> {
        match *self {
            Spec::Damage        => vec![Stat::BlueDamage, Stat::RedDamage, Stat::GreenDamage],
            Spec::RedDamageI    => vec![Stat::RedDamage],
            Spec::GreenDamageI  => vec![Stat::GreenDamage],
            Spec::BlueDamageI   => vec![Stat::BlueDamage],
            Spec::GRDI          => vec![Stat::GreenDamage, Stat::RedDamage],
            Spec::GBDI          => vec![Stat::GreenDamage, Stat::BlueDamage],
            Spec::RBDI          => vec![Stat::RedDamage, Stat::BlueDamage],

            Spec::Speed         => vec![Stat::Speed],
            Spec::RedSpeedI     => vec![Stat::Speed],
            Spec::BlueSpeedI    => vec![Stat::Speed],
            Spec::GreenSpeedI   => vec![Stat::Speed],
            Spec::GRSpeedI      => vec![Stat::Speed],
            Spec::GBSpeedI      => vec![Stat::Speed],
            Spec::RBSpeedI      => vec![Stat::Speed],

            Spec::Hp            => vec![Stat::Hp],
            Spec::RedShieldI    => vec![Stat::RedShield],
            Spec::BlueShieldI   => vec![Stat::BlueShield],
            Spec::LifeI         => vec![Stat::Hp],
            Spec::LRSI          => vec![Stat::Hp, Stat::RedShield],
            Spec::LBSI          => vec![Stat::Hp, Stat::BlueShield],
            Spec::RBSI          => vec![Stat::BlueShield, Stat::RedShield],

        }
    }

    pub fn apply(&self, modified: u64, base: u64, team_colours: &Colours) -> u64 {
        match *self {
            // Upgrades to Damage Spec
            Spec::Damage            => modified + base.pct(5),
            Spec::RedDamageI        => modified + {
                let mut pct = 5;
                if team_colours.red >= 5  { pct += 5 };
                if team_colours.red >= 10 { pct += 10 };
                if team_colours.red >= 20 { pct += 20 };
                base.pct(pct)
            },
            Spec::GreenDamageI        => modified + {
                let mut pct = 5;
                if team_colours.green >= 5  { pct += 5 };
                if team_colours.green >= 10 { pct += 10 };
                if team_colours.green >= 20 { pct += 20 };
                base.pct(pct)
            },
            Spec::BlueDamageI        => modified + {
                let mut pct = 5;
                if team_colours.blue >= 5  { pct += 10 };
                if team_colours.blue >= 10 { pct += 20 };
                if team_colours.blue >= 20 { pct += 30 };
                base.pct(pct)
            },
            Spec::GRDI              => modified + {
                let mut pct = 5;
                if team_colours.green >= 2 && team_colours.red >= 2 { pct += 5 };
                if team_colours.green >= 5 && team_colours.red >= 5 { pct += 10 };
                if team_colours.green >= 10 && team_colours.red >= 10 { pct += 20 };
                base.pct(pct)
            },
            Spec::GBDI              => modified + {
                let mut pct = 5;
                if team_colours.green >= 2 && team_colours.blue >= 2 { pct += 5 };
                if team_colours.green >= 5 && team_colours.blue >= 5 { pct += 10 };
                if team_colours.green >= 10 && team_colours.blue >= 10 { pct += 20 };
                base.pct(pct)
            },
            Spec::RBDI              => modified + {
                let mut pct = 5;
                if team_colours.blue >= 2 && team_colours.red >= 2 { pct += 5 };
                if team_colours.blue >= 5 && team_colours.red >= 5 { pct += 10 };
                if team_colours.blue >= 10 && team_colours.red >= 10 { pct += 20 };
                base.pct(pct)
            },
            // Upgrades to speed Spec
            Spec::Speed            => modified + base.pct(5),
            Spec::RedSpeedI        => modified + {
                let mut pct = 5;
                if team_colours.red >= 5  { pct += 5 };
                if team_colours.red >= 10 { pct += 10 };
                if team_colours.red >= 20 { pct += 20 };
                base.pct(pct)
            },
            Spec::GreenSpeedI        => modified + {
                let mut pct = 5;
                if team_colours.green >= 5  { pct += 5 };
                if team_colours.green >= 10 { pct += 10 };
                if team_colours.green >= 20 { pct += 20 };
                base.pct(pct)
            },
            Spec::BlueSpeedI        => modified + {
                let mut pct = 5;
                if team_colours.blue >= 5  { pct += 5 };
                if team_colours.blue >= 10 { pct += 10 };
                if team_colours.blue >= 20 { pct += 20 };
                base.pct(pct)
            },
            Spec::GRSpeedI              => modified + {
                let mut pct = 5;
                if team_colours.green >= 2 && team_colours.red >= 2 { pct += 5 };
                if team_colours.green >= 5 && team_colours.red >= 5 { pct += 10 };
                if team_colours.green >= 10 && team_colours.red >= 10 { pct += 20 };
                base.pct(pct)
            },
            Spec::GBSpeedI              => modified + {
                let mut pct = 5;
                if team_colours.green >= 2 && team_colours.blue >= 2 { pct += 5 };
                if team_colours.green >= 5 && team_colours.blue >= 5 { pct += 10 };
                if team_colours.green >= 10 && team_colours.blue >= 10 { pct += 20 };
                base.pct(pct)
            },
            Spec::RBSpeedI              => modified + {
                let mut pct = 5;
                if team_colours.blue >= 2 && team_colours.red >= 2 { pct += 5 };
                if team_colours.blue >= 5 && team_colours.red >= 5 { pct += 10 };
                if team_colours.blue >= 10 && team_colours.red >= 10 { pct += 20 };
                base.pct(pct)
            },

            // Upgrades to HP Spec
            Spec::Hp                => modified + base.pct(5),
            Spec::LifeI             => modified + {
                let mut mult: u64 = 10;
                if team_colours.red >= 5  { mult += 20 };
                if team_colours.red >= 10  { mult += 30 };
                if team_colours.red >= 20  { mult += 50 };
                mult * team_colours.green as u64
            },
            Spec::RedShieldI        => modified + {
                let mut mult: u64 = 10;
                if team_colours.red >= 5  { mult += 20 };
                if team_colours.red >= 10  { mult += 30 };
                if team_colours.red >= 20  { mult += 50 };
                mult * team_colours.red as u64
            },
            Spec::BlueShieldI       => modified + {
                let mut mult: u64 = 10;
                if team_colours.red >= 5  { mult += 20 };
                if team_colours.red >= 10  { mult += 30 };
                if team_colours.red >= 20  { mult += 50 };
                mult * team_colours.blue as u64
            },
            Spec::LRSI              => modified + {
                let mut mult: u64 = 5;
                if team_colours.green >= 2 && team_colours.red >= 2 { mult += 5 };
                if team_colours.green >= 5 && team_colours.red >= 5 { mult += 10 };
                if team_colours.green >= 10 && team_colours.red >= 10 { mult += 20 };
                mult * (team_colours.green + team_colours.red) as u64
            },
            Spec::LBSI              => modified + {
                let mut mult: u64 = 5;
                if team_colours.green >= 2 && team_colours.red >= 2 { mult += 5 };
                if team_colours.green >= 5 && team_colours.red >= 5 { mult += 10 };
                if team_colours.green >= 10 && team_colours.red >= 10 { mult += 20 };
                mult * (team_colours.green + team_colours.red) as u64
            },
            Spec::RBSI              => modified + {
                let mut mult: u64 = 5;
                if team_colours.blue >= 2 && team_colours.red >= 2 { mult += 5 };
                if team_colours.blue >= 5 && team_colours.red >= 5 { mult += 10 };
                if team_colours.blue >= 10 && team_colours.red >= 10 { mult += 20 };
                mult * (team_colours.blue + team_colours.red) as u64
            },
        }
    }
}
