1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use serde::{Deserialize, Serialize};
use time::Month;

#[derive(Debug, Clone)]
pub enum SeasonError {
    InvalidSeason,
    ParseFailed(String),
}

#[derive(Debug, Clone)]
pub struct SeasonBuilder {
    season: Season,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Season {
    #[serde(rename = "id")]
    id: String,
    #[serde(skip_deserializing, skip_serializing)]
    year: i32,
    #[serde(skip_deserializing, skip_serializing, default = "Season::default_month")]
    month: Month,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PreviousSeasonData {
    pub id: String,
    pub rank: i32,
    pub trophies: i32,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct BestSeasonData {
    pub id: String,
    pub rank: i32,
    pub trophies: i32,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct PreviousVersusSeasonData {
    pub id: String,
    pub rank: i32,
    pub trophies: i32,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct BestVersusSeasonData {
    pub id: String,
    pub rank: i32,
    pub trophies: i32,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct CurrentSeasonData {
    pub id: Option<String>,
    pub rank: Option<i32>,
    pub trophies: i32,
}

impl From<std::num::ParseIntError> for SeasonError {
    fn from(err: std::num::ParseIntError) -> Self {
        Self::ParseFailed(err.to_string())
    }
}

impl SeasonBuilder {
    const fn new() -> Self {
        Self { season: Season { id: String::new(), year: 2015, month: Month::July } }
    }

    #[must_use]
    pub const fn year(mut self, year: i32) -> Self {
        self.season.year = year;
        self
    }

    #[must_use]
    pub const fn month(mut self, month: Month) -> Self {
        self.season.month = month;
        self
    }

    #[must_use]
    pub fn build(mut self) -> Season {
        self.season.id = format!("{}-{:02}", self.season.year, self.season.month as i32);
        self.season
    }
}

impl Season {
    #[must_use]
    pub const fn default_month() -> Month {
        Month::July
    }

    #[must_use]
    pub const fn builder() -> SeasonBuilder {
        SeasonBuilder::new()
    }
}

impl std::str::FromStr for Season {
    type Err = SeasonError;

    fn from_str(season: &str) -> Result<Self, Self::Err> {
        let mut season_split = season.split('-');
        Ok(Self {
            id: season.to_string(),
            year: season_split.next().ok_or(SeasonError::InvalidSeason)?.parse()?,
            month: Month::try_from(
                season_split.next().ok_or(SeasonError::InvalidSeason)?.parse::<u8>()?,
            )
            .unwrap(),
        })
    }
}

impl std::fmt::Display for Season {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let mut season_split = self.id.split('-');
        let year = season_split.next().unwrap().parse::<i32>().unwrap();
        let month = Month::try_from(season_split.next().unwrap().parse::<u8>().unwrap()).unwrap();
        write!(f, "{year}-{:02}", month as i32)
    }
}