use chrono::{DateTime, Duration};
use rspotify::model::*;
use serde::de::DeserializeOwned;
use wasm_bindgen_test::*;

#[track_caller]
fn deserialize<T>(data: impl AsRef<str>) -> T
where
    T: DeserializeOwned + PartialEq + std::fmt::Debug,
{
    println!("from_str");
    let value = serde_json::from_str(data.as_ref()).unwrap();

    // Also deserialize the string as an std::io::Reader to ensure we aren't making any assumptions about borrowing input
    println!("from_reader");
    let _: T = serde_json::from_reader(data.as_ref().as_bytes()).unwrap();

    value
}

#[test]
#[wasm_bindgen_test]
fn test_simplified_track() {
    let json_str = r#"
    {
      "album": {
        "album_type": "album",
        "total_tracks": 11,
        "available_markets": ["AR", "AU", "AT", "BE", "BO", "BR", "BG", "CA", "CL", "CO", "CR", "CY", "CZ", "DK", "DO", "DE", "EC", "EE", "SV", "FI", "FR", "GR", "GT", "HN", "HK", "HU", "IS", "IE", "IT", "LV", "LT", "LU", "MY", "MT", "MX", "NL", "NZ", "NI", "NO", "PA", "PY", "PE", "PH", "PL", "PT", "SG", "SK", "ES", "SE", "CH", "TW", "TR", "UY", "US", "GB", "AD", "LI", "MC", "ID", "JP", "TH", "VN", "RO", "IL", "ZA", "SA", "AE", "BH", "QA", "OM", "KW", "EG", "MA", "DZ", "TN", "LB", "JO", "PS", "IN", "BY", "KZ", "MD", "UA", "AL", "BA", "HR", "ME", "MK", "RS", "SI", "KR", "BD", "PK", "LK", "GH", "KE", "NG", "TZ", "UG", "AG", "AM", "BS", "BB", "BZ", "BT", "BW", "BF", "CV", "CW", "DM", "FJ", "GM", "GE", "GD", "GW", "GY", "HT", "JM", "KI", "LS", "LR", "MW", "MV", "ML", "MH", "FM", "NA", "NR", "NE", "PW", "PG", "WS", "SM", "ST", "SN", "SC", "SL", "SB", "KN", "LC", "VC", "SR", "TL", "TO", "TT", "TV", "VU", "AZ", "BN", "BI", "KH", "CM", "TD", "KM", "GQ", "SZ", "GA", "GN", "KG", "LA", "MO", "MR", "MN", "NP", "RW", "TG", "UZ", "ZW", "BJ", "MG", "MU", "MZ", "AO", "CI", "DJ", "ZM", "CD", "CG", "IQ", "LY", "TJ", "VE", "ET", "XK"],
        "external_urls": {
          "spotify": "https://open.spotify.com/album/6akEvsycLGftJxYudPjmqK"
        },
        "href": "https://api.spotify.com/v1/albums/6akEvsycLGftJxYudPjmqK",
        "id": "6akEvsycLGftJxYudPjmqK",
        "images": [
          {
            "url": "https://i.scdn.co/image/ab67616d0000b2731ae2bdc1378da1b440e1f610",
            "height": 640,
            "width": 640
          },
          {
            "url": "https://i.scdn.co/image/ab67616d00001e021ae2bdc1378da1b440e1f610",
            "height": 300,
            "width": 300
          },
          {
            "url": "https://i.scdn.co/image/ab67616d000048511ae2bdc1378da1b440e1f610",
            "height": 64,
            "width": 64
          }
        ],
        "name": "Place In The Sun",
        "release_date": "2004-02-02",
        "release_date_precision": "day",
        "type": "album",
        "uri": "spotify:album:6akEvsycLGftJxYudPjmqK",
        "artists": [
          {
            "external_urls": {
              "spotify": "https://open.spotify.com/artist/08td7MxkoHQkXnWAYD8d6Q"
            },
            "href": "https://api.spotify.com/v1/artists/08td7MxkoHQkXnWAYD8d6Q",
            "id": "08td7MxkoHQkXnWAYD8d6Q",
            "name": "Tania Bowra",
            "type": "artist",
            "uri": "spotify:artist:08td7MxkoHQkXnWAYD8d6Q"
          }
        ]
      },
    "artists": [ {
      "external_urls": {
        "spotify": "https://open.spotify.com/artist/08td7MxkoHQkXnWAYD8d6Q"
      },
      "href": "https://api.spotify.com/v1/artists/08td7MxkoHQkXnWAYD8d6Q",
      "id": "08td7MxkoHQkXnWAYD8d6Q",
      "name": "Tania Bowra",
      "type": "artist",
      "uri": "spotify:artist:08td7MxkoHQkXnWAYD8d6Q"
    } ],
    "available_markets": ["US"],
    "disc_number": 1,
    "duration_ms": 276773,
    "explicit": false,
    "external_urls": {
      "spotify": "https://open.spotify.com/track/2TpxZ7JUBn3uw46aR7qd6V"
    },
    "href": "https://api.spotify.com/v1/tracks/2TpxZ7JUBn3uw46aR7qd6V",
    "id": "2TpxZ7JUBn3uw46aR7qd6V",
    "name": "All I Want",
    "preview_url": "https://p.scdn.co/mp3-preview/6d00206e32194d15df329d4770e4fa1f2ced3f57",
    "track_number": 1,
    "type": "track",
    "uri": "spotify:track:2TpxZ7JUBn3uw46aR7qd6V",
    "is_local": false
  }

"#;
    let track: SimplifiedTrack = deserialize(json_str);
    let duration = Duration::try_milliseconds(276773).unwrap();
    assert_eq!(track.duration, duration);
}

#[test]
#[wasm_bindgen_test]
fn test_public_user() {
    let json_str = r#"
        {
            "display_name": "Ronald Pompa",
            "external_urls": {
                "spotify": "https://open.spotify.com/user/wizzler_with_underscores"
            },
            "followers": {
                "href": null,
                "total": 4050
            },
            "href": "https://api.spotify.com/v1/users/wizzler_with_underscores",
            "id": "wizzler_with_underscores",
            "images": [
                {
                "height": null,
                "url": "https://i.scdn.co/image/ab6775700000ee85b5d374d281b9e510eda15fdf",
                "width": null
                }
            ],
            "type": "user",
            "uri": "spotify:user:wizzler_with_underscores"
        }
        "#;
    let user: PublicUser = deserialize(json_str);
    // This also makes sure user IDs can have other characters, such as
    // underscores.
    assert_eq!(
        user.id,
        UserId::from_id("wizzler_with_underscores").unwrap()
    );
}

#[test]
#[wasm_bindgen_test]
fn test_private_user() {
    let json_str = r#"
        {
            "country": "US",
            "display_name": "Sergey",
            "email": "vixatew967@top-email.org",
            "explicit_content": {
              "filter_enabled": false,
              "filter_locked": false
            },
            "external_urls": {
              "spotify": "https://open.spotify.com/user/waq5aexykhm6nlv0cnwdieng0"
            },
            "followers": {
              "href": null,
              "total": 0
            },
            "href": "https://api.spotify.com/v1/users/waq5aexykhm6nlv0cnwdieng0",
            "id": "waq5aexykhm6nlv0cnwdieng0",
            "images": [],
            "product": "open",
            "type": "user",
            "uri": "spotify:user:waq5aexykhm6nlv0cnwdieng0"
          }
        "#;
    let private_user: PrivateUser = deserialize(json_str);
    assert_eq!(private_user.display_name.unwrap(), "Sergey");
}

#[test]
#[wasm_bindgen_test]
fn test_full_artist() {
    let json_str = r#"
        {
            "external_urls": {
                "spotify": "https://open.spotify.com/artist/0OdUWJ0sBjDrqHygGUXeCF"
            },
            "followers": {
                "href": null,
                "total": 833247
            },
            "genres": [
                "indie folk"
            ],
            "href": "https://api.spotify.com/v1/artists/0OdUWJ0sBjDrqHygGUXeCF",
            "id": "0OdUWJ0sBjDrqHygGUXeCF",
            "images": [
                {
                    "height": 640,
                    "url": "https://i.scdn.co/image/0f9a5013134de288af7d49a962417f4200539b47",
                    "width": 640
                }
            ],
            "name": "Band of Horses",
            "popularity": 65,
            "type": "artist",
            "uri": "spotify:artist:0OdUWJ0sBjDrqHygGUXeCF"
        }
        "#;
    let full_artist: FullArtist = deserialize(json_str);
    assert_eq!(full_artist.name, "Band of Horses");
}

#[test]
#[wasm_bindgen_test]
fn test_simplified_episode() {
    let json_str = r#"
        {
            "audio_preview_url": "https://p.scdn.co/mp3-preview/d8b916e1872de2bb0285d8c7bfe2b4b57011c85c",
            "description": "En unik barockträdgård från 1600-talet gömmer sig på Södermalm i Stockholm och nu gräver arkeologerna ut parken och kvarteret där Bellman lekte som barn.  Nu grävs Carl Michael Bellmans kvarter fram på Södermalm i Stockholm. Under dagens jordyta döljer sig en rik barockträdgård, men också tunga industrier från en tid då Söder var stockholmarnas sommarnöje. Dessutom om hur arkeologer ska kunna bli bättre att hitta de fattigas kulturarv. För vid sidan av slott, borgar och hallar finns torpen och backstugorna som utgör ett fortfarande okänt kulturarv som angår oss alla. Programledare Tobias Svanelid.",
            "duration_ms": 2685023,
            "explicit": false,
            "external_urls": {
                "spotify": "https://open.spotify.com/episode/3brfPv3PaUhspkm1T9ZVl8"
            },
            "href": "https://api.spotify.com/v1/episodes/3brfPv3PaUhspkm1T9ZVl8",
            "id": "3brfPv3PaUhspkm1T9ZVl8",
            "images": [
                {
                "height": 640,
                "url": "https://i.scdn.co/image/65497c8c1bef1b783d2be6a1c73b294d953f9406",
                "width": 640
                }
            ],
            "is_externally_hosted": false,
            "is_playable": true,
            "language": "sv",
            "languages": [
                "sv"
            ],
            "name": "På Bellmans bakgata",
            "release_date": "2020-10-20",
            "release_date_precision": "day",
            "resume_point": {
                "fully_played": false,
                "resume_position_ms": 0
            },
            "type": "episode",
            "uri": "spotify:episode:3brfPv3PaUhspkm1T9ZVl8"
        }
        "#;
    let simplified_episode: SimplifiedEpisode = deserialize(json_str);
    assert_eq!(
        simplified_episode.release_date_precision,
        DatePrecision::Day
    );
    let duration = Duration::try_milliseconds(2685023).unwrap();
    assert_eq!(simplified_episode.duration, duration);
}

#[test]
#[wasm_bindgen_test]
fn test_full_episode() {
    let json_str = r#"
    {
        "audio_preview_url": "https://p.scdn.co/mp3-preview/566fcc94708f39bcddc09e4ce84a8e5db8f07d4d",
        "description": "En ny tysk ",
        "duration_ms": 1502795,
        "explicit": false,
        "external_urls": {
            "spotify": "https://open.spotify.com/episode/512ojhOuo1ktJprKbVcKyQ"
        },
        "href": "https://api.spotify.com/v1/episodes/512ojhOuo1ktJprKbVcKyQ",
        "id": "512ojhOuo1ktJprKbVcKyQ",
        "images": [
            {
                "height": 64,
                "url": "https://i.scdn.co/image/e29c75799cad73927fad713011edad574868d8da",
                "width": 64
            }
        ],
        "is_externally_hosted": false,
        "is_playable": true,
        "language": "sv",
        "languages": [
            "sv"
        ],
        "name": "Tredje rikets knarkande granskas",
        "release_date": "2015-10-01",
        "release_date_precision": "day",
        "show": {
            "available_markets": [
                "ZA"
            ],
            "copyrights": [],
            "description": "Vi är där historien är. Ansvarig utgivare: Nina Glans",
            "explicit": false,
            "external_urls": {
                "spotify": "https://open.spotify.com/show/38bS44xjbVVZ3No3ByF1dJ"
            },
            "href": "https://api.spotify.com/v1/shows/38bS44xjbVVZ3No3ByF1dJ",
            "id": "38bS44xjbVVZ3No3ByF1dJ",
            "images": [
                {
                    "height": 64,
                    "url": "https://i.scdn.co/image/3dc007829bc0663c24089e46743a9f4ae15e65f8",
                    "width": 64
                }
            ],
            "is_externally_hosted": false,
            "languages": [
                "sv"
            ],
            "media_type": "audio",
            "name": "Vetenskapsradion Historia",
            "publisher": "Sveriges Radio",
            "type": "show",
            "uri": "spotify:show:38bS44xjbVVZ3No3ByF1dJ"
        },
        "type": "episode",
        "uri": "spotify:episode:512ojhOuo1ktJprKbVcKyQ"
    }
        "#;
    let full_episode: FullEpisode = deserialize(json_str);
    assert_eq!(full_episode.release_date_precision, DatePrecision::Day);
    let duration = Duration::try_milliseconds(1502795).unwrap();
    assert_eq!(full_episode.duration, duration);
}

#[test]
#[wasm_bindgen_test]
fn test_copyright() {
    let json_str = r#"
	[ {
	    "text" : "(P) 2000 Sony Music Entertainment Inc.",
	    "type" : "P"
	} ]

"#;
    let copyrights: Vec<Copyright> = deserialize(json_str);
    assert_eq!(copyrights[0]._type, CopyrightType::Performance);
}

#[test]
#[wasm_bindgen_test]
fn test_audio_analysis_section() {
    let json_str = r#"
        {
            "start": 237.02356,
            "duration": 18.32542,
            "confidence": 1,
            "loudness": -20.074,
            "tempo": 98.253,
            "tempo_confidence": 0.767,
            "key": 5,
            "key_confidence": 0.327,
            "mode": 1,
            "mode_confidence": 0.566,
            "time_signature": 4,
            "time_signature_confidence": 1
        }
        "#;
    let session: AudioAnalysisSection = deserialize(json_str);
    // Comparison of floating point numbers
    assert!((session.time_interval.duration - 18.32542).abs() < f32::EPSILON);
}

#[test]
#[wasm_bindgen_test]
fn test_audio_analysis_segments() {
    let json_str = r#"
         {
            "start": 252.15601,
            "duration": 3.19297,
            "confidence": 0.522,
            "loudness_start": -23.356,
            "loudness_max_time": 0.06971,
            "loudness_max": -18.121,
            "loudness_end": -60,
            "pitches": [
                0.15
            ],
            "timbre": [
                -19.037
            ]
            }
            "#;
    let segment: AudioAnalysisSegment = deserialize(json_str);
    // Comparison of floating point numbers
    assert!((segment.time_interval.start - 252.156).abs() < f32::EPSILON);
}

#[test]
#[wasm_bindgen_test]
fn test_actions() {
    let json_str = r#"
        {
            "disallows": {
                "resuming": true
            }
        }
        "#;
    let actions: Actions = deserialize(json_str);
    assert_eq!(actions.disallows[0], DisallowKey::Resuming);
}

#[test]
#[wasm_bindgen_test]
fn test_recommendations_seed() {
    let json_str = r#"
        {
            "initialPoolSize": 500,
            "afterFilteringSize": 380,
            "afterRelinkingSize": 365,
            "href": "https://api.spotify.com/v1/artists/4NHQUGzhtTLFvgF5SZesLK",
            "id": "4NHQUGzhtTLFvgF5SZesLK",
            "type": "ARTIST"
        }
        "#;
    let seed: RecommendationsSeed = deserialize(json_str);
    assert_eq!(seed._type, RecommendationsSeedType::Artist);
}

#[test]
#[wasm_bindgen_test]
fn test_full_playlist() {
    let json_str_images = r#"
[
    {
	"height": null,
	"url": "https://i.scdn.co/image/ab67706c0000bebb8d0ce13d55f634e290f744ba",
	"width": null
    }
]
"#;
    let json_str_simplified_artists = r#"
[
    {
	"external_urls": {
	    "spotify": "https://open.spotify.com/artist/5I8r2w4hf7OYp2cunjihxJ"
	},
	"href": "https://api.spotify.com/v1/artists/5I8r2w4hf7OYp2cunjihxJ",
	"id": "5I8r2w4hf7OYp2cunjihxJ",
	"name": "Kularis",
	"type": "artist",
	"uri": "spotify:artist:5I8r2w4hf7OYp2cunjihxJ"
    }
]
"#;
    let json_str = r#"
        {
            "collaborative": false,
            "description": "A playlist for testing pourposes",
            "external_urls": {
                "spotify": "https://open.spotify.com/playlist/3cEYpjA9oz9GiPac4AsH4n"
            },
            "followers": {
                "href": null,
                "total": 109
            },
            "href": "https://api.spotify.com/v1/playlists/3cEYpjA9oz9GiPac4AsH4n",
            "id": "3cEYpjA9oz9GiPac4AsH4n",
            "images": json_str_images,
            "name": "Spotify Web API Testing playlist",
            "owner": {
                "display_name": "JMPerez²",
                "external_urls": {
                    "spotify": "https://open.spotify.com/user/jmperezperez"
                },
                "href": "https://api.spotify.com/v1/users/jmperezperez",
                "id": "jmperezperez",
                "type": "user",
                "uri": "spotify:user:jmperezperez"
            },
            "primary_color": null,
            "public": true,
            "snapshot_id": "MTgsZWFmNmZiNTIzYTg4ODM0OGQzZWQzOGI4NTdkNTJlMjU0OWFkYTUxMA==",
            "tracks": {
                "href": "https://api.spotify.com/v1/playlists/3cEYpjA9oz9GiPac4AsH4n/tracks?offset=0&limit=100",
                "items": [
                    {
                        "added_at": "2015-01-15T12:39:22Z",
                        "added_by": {
                            "external_urls": {
                                "spotify": "https://open.spotify.com/user/jmperezperez"
                            },
                            "href": "https://api.spotify.com/v1/users/jmperezperez",
                            "id": "jmperezperez",
                            "type": "user",
                            "uri": "spotify:user:jmperezperez"
                        },
                        "is_local": false,
                        "primary_color": null,
                        "track": {
                            "album": {
                                "album_type": "album",
                                "artists": json_str_simplified_artists,
                                "available_markets": [
                                    "US"
                                ],
                                "external_urls": {
                                    "spotify": "https://open.spotify.com/album/2pANdqPvxInB0YvcDiw4ko"
                                },
                                "href": "https://api.spotify.com/v1/albums/2pANdqPvxInB0YvcDiw4ko",
                                "id": "2pANdqPvxInB0YvcDiw4ko",
                                "images": json_str_images,
                                "name": "Progressive Psy Trance Picks Vol.8",
                                "release_date": "2012-04-02",
                                "release_date_precision": "day",
                                "total_tracks": 20,
                                "type": "album",
                                "uri": "spotify:album:2pANdqPvxInB0YvcDiw4ko"
                            },
                            "artists": json_str_simplified_artists,
                            "available_markets": [
                                "US"
                            ],
                            "disc_number": 1,
                            "duration_ms": 376000,
                            "episode": false,
                            "explicit": false,
                            "external_ids": {
                                "isrc": "DEKC41200989"
                            },
                            "external_urls": {
                                "spotify": "https://open.spotify.com/track/4rzfv0JLZfVhOhbSQ8o5jZ"
                            },
                            "href": "https://api.spotify.com/v1/tracks/4rzfv0JLZfVhOhbSQ8o5jZ",
                            "id": "4rzfv0JLZfVhOhbSQ8o5jZ",
                            "is_local": false,
                            "name": "Api",
                            "popularity": 2,
                            "preview_url": "https://p.scdn.co/mp3-preview/c440fa9ff320fb74629f8477bff45b1a377897ab?cid=774b29d4f13844c495f206cafdad9c86",
                            "track": true,
                            "track_number": 10,
                            "type": "track",
                            "uri": "spotify:track:4rzfv0JLZfVhOhbSQ8o5jZ"
                        },
                        "video_thumbnail": {
                            "url": null
                        }
                    }
                ],
                "limit": 100,
                "next": null,
                "offset": 0,
                "previous": null,
                "total": 5
            },
            "type": "playlist",
            "uri": "spotify:playlist:3cEYpjA9oz9GiPac4AsH4n"
        }
        "#.replace("json_str_images", json_str_images).replace("json_str_simplified_artists", json_str_simplified_artists);
    let full_playlist: FullPlaylist = deserialize(json_str);
    assert_eq!(
        full_playlist.id.uri(),
        "spotify:playlist:3cEYpjA9oz9GiPac4AsH4n".to_string()
    );
    assert_eq!(full_playlist.followers.total, 109);
    assert_eq!(full_playlist.items.total, 5);
    #[allow(deprecated)]
    {
        assert_eq!(full_playlist.tracks.total, 5);
    }
}

#[test]
#[wasm_bindgen_test]
fn test_full_playlist_accepts_items_field() {
    // yes the pourposes typo comes from the official spotify api ._.
    let json = r#"
    {
      "collaborative": false,
      "description": "A playlist for testing pourposes",
      "external_urls": {
        "spotify": "https://open.spotify.com/playlist/3cEYpjA9oz9GiPac4AsH4n"
      },
      "href": "https://api.spotify.com/v1/playlists/3cEYpjA9oz9GiPac4AsH4n?locale=en-US%2Cen%3Bq%3D0.9",
      "id": "3cEYpjA9oz9GiPac4AsH4n",
      "images": [
        {
          "url": "https://image-cdn-ak.spotifycdn.com/image/ab67706c0000da848d0ce13d55f634e290f744ba",
          "height": null,
          "width": null
        }
      ],
      "name": "Spotify Web API Testing playlist",
      "owner": {
        "external_urls": {
          "spotify": "https://open.spotify.com/user/jmperezperez"
        },
        "href": "https://api.spotify.com/v1/users/jmperezperez",
        "id": "jmperezperez",
        "type": "user",
        "uri": "spotify:user:jmperezperez",
        "display_name": "JMPerez²"
      },
      "public": true,
      "snapshot_id": "AAAAEur2+1I6iINI0+04uFfVLiVJraUQ",
      "items": {
        "href": "https://api.spotify.com/v1/playlists/3cEYpjA9oz9GiPac4AsH4n/items?offset=0&limit=100&locale=en-US,en;q%3D0.9",
        "limit": 100,
        "next": null,
        "offset": 0,
        "previous": null,
        "total": 5,
        "items": [
          {
            "added_at": "2015-01-15T12:39:22Z",
            "added_by": {
              "external_urls": {
                "spotify": "https://open.spotify.com/user/jmperezperez"
              },
              "href": "https://api.spotify.com/v1/users/jmperezperez",
              "id": "jmperezperez",
              "type": "user",
              "uri": "spotify:user:jmperezperez"
            },
            "is_local": false,
            "item": {
              "album": {
                "album_type": "compilation",
                "total_tracks": 20,
                "available_markets": [],
                "external_urls": {
                  "spotify": "https://open.spotify.com/album/2pANdqPvxInB0YvcDiw4ko"
                },
                "href": "https://api.spotify.com/v1/albums/2pANdqPvxInB0YvcDiw4ko",
                "id": "2pANdqPvxInB0YvcDiw4ko",
                "images": [
                  {
                    "url": "https://i.scdn.co/image/ab67616d0000b273ce6d0eef0c1ce77e5f95bbbc",
                    "height": 640,
                    "width": 640
                  },
                  {
                    "url": "https://i.scdn.co/image/ab67616d00001e02ce6d0eef0c1ce77e5f95bbbc",
                    "height": 300,
                    "width": 300
                  },
                  {
                    "url": "https://i.scdn.co/image/ab67616d00004851ce6d0eef0c1ce77e5f95bbbc",
                    "height": 64,
                    "width": 64
                  }
                ],
                "name": "Progressive Psy Trance Picks Vol.8",
                "release_date": "2012-04-02",
                "release_date_precision": "day",
                "type": "album",
                "uri": "spotify:album:2pANdqPvxInB0YvcDiw4ko",
                "artists": [
                  {
                    "external_urls": {
                      "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of"
                    },
                    "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of",
                    "id": "0LyfQWJT6nXafLPZqxe9Of",
                    "name": "Various Artists",
                    "type": "artist",
                    "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of"
                  }
                ]
              },
              "artists": [
                {
                  "external_urls": {
                    "spotify": "https://open.spotify.com/artist/6eSdhw46riw2OUHgMwR8B5"
                  },
                  "href": "https://api.spotify.com/v1/artists/6eSdhw46riw2OUHgMwR8B5",
                  "id": "6eSdhw46riw2OUHgMwR8B5",
                  "name": "Odiseo",
                  "type": "artist",
                  "uri": "spotify:artist:6eSdhw46riw2OUHgMwR8B5"
                }
              ],
              "available_markets": [],
              "disc_number": 1,
              "duration_ms": 376000,
              "explicit": false,
              "external_ids": {
                "isrc": "DEKC41200989"
              },
              "external_urls": {
                "spotify": "https://open.spotify.com/track/4rzfv0JLZfVhOhbSQ8o5jZ"
              },
              "href": "https://api.spotify.com/v1/tracks/4rzfv0JLZfVhOhbSQ8o5jZ",
              "id": "4rzfv0JLZfVhOhbSQ8o5jZ",
              "name": "Api",
              "popularity": 6,
              "preview_url": null,
              "track_number": 10,
              "type": "track",
              "uri": "spotify:track:4rzfv0JLZfVhOhbSQ8o5jZ",
              "is_local": false,
              "episode": false,
              "track": true
            },
            "track": {
              "album": {
                "album_type": "compilation",
                "total_tracks": 20,
                "available_markets": [],
                "external_urls": {
                  "spotify": "https://open.spotify.com/album/2pANdqPvxInB0YvcDiw4ko"
                },
                "href": "https://api.spotify.com/v1/albums/2pANdqPvxInB0YvcDiw4ko",
                "id": "2pANdqPvxInB0YvcDiw4ko",
                "images": [
                  {
                    "url": "https://i.scdn.co/image/ab67616d0000b273ce6d0eef0c1ce77e5f95bbbc",
                    "height": 640,
                    "width": 640
                  },
                  {
                    "url": "https://i.scdn.co/image/ab67616d00001e02ce6d0eef0c1ce77e5f95bbbc",
                    "height": 300,
                    "width": 300
                  },
                  {
                    "url": "https://i.scdn.co/image/ab67616d00004851ce6d0eef0c1ce77e5f95bbbc",
                    "height": 64,
                    "width": 64
                  }
                ],
                "name": "Progressive Psy Trance Picks Vol.8",
                "release_date": "2012-04-02",
                "release_date_precision": "day",
                "type": "album",
                "uri": "spotify:album:2pANdqPvxInB0YvcDiw4ko",
                "artists": [
                  {
                    "external_urls": {
                      "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of"
                    },
                    "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of",
                    "id": "0LyfQWJT6nXafLPZqxe9Of",
                    "name": "Various Artists",
                    "type": "artist",
                    "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of"
                  }
                ]
              },
              "artists": [
                {
                  "external_urls": {
                    "spotify": "https://open.spotify.com/artist/6eSdhw46riw2OUHgMwR8B5"
                  },
                  "href": "https://api.spotify.com/v1/artists/6eSdhw46riw2OUHgMwR8B5",
                  "id": "6eSdhw46riw2OUHgMwR8B5",
                  "name": "Odiseo",
                  "type": "artist",
                  "uri": "spotify:artist:6eSdhw46riw2OUHgMwR8B5"
                }
              ],
              "available_markets": [],
              "disc_number": 1,
              "duration_ms": 376000,
              "explicit": false,
              "external_ids": {
                "isrc": "DEKC41200989"
              },
              "external_urls": {
                "spotify": "https://open.spotify.com/track/4rzfv0JLZfVhOhbSQ8o5jZ"
              },
              "href": "https://api.spotify.com/v1/tracks/4rzfv0JLZfVhOhbSQ8o5jZ",
              "id": "4rzfv0JLZfVhOhbSQ8o5jZ",
              "name": "Api",
              "popularity": 6,
              "preview_url": null,
              "track_number": 10,
              "type": "track",
              "uri": "spotify:track:4rzfv0JLZfVhOhbSQ8o5jZ",
              "is_local": false,
              "episode": false,
              "track": true
            },
            "primary_color": null,
            "video_thumbnail": {
              "url": null
            }
          }
        ]
      },
      "tracks": {
        "href": "https://api.spotify.com/v1/playlists/3cEYpjA9oz9GiPac4AsH4n/tracks?offset=0&limit=100&locale=en-US,en;q%3D0.9",
        "limit": 100,
        "next": null,
        "offset": 0,
        "previous": null,
        "total": 5,
        "items": [
          {
            "added_at": "2015-01-15T12:39:22Z",
            "added_by": {
              "external_urls": {
                "spotify": "https://open.spotify.com/user/jmperezperez"
              },
              "href": "https://api.spotify.com/v1/users/jmperezperez",
              "id": "jmperezperez",
              "type": "user",
              "uri": "spotify:user:jmperezperez"
            },
            "is_local": false,
            "item": {
              "album": {
                "album_type": "compilation",
                "total_tracks": 20,
                "available_markets": [],
                "external_urls": {
                  "spotify": "https://open.spotify.com/album/2pANdqPvxInB0YvcDiw4ko"
                },
                "href": "https://api.spotify.com/v1/albums/2pANdqPvxInB0YvcDiw4ko",
                "id": "2pANdqPvxInB0YvcDiw4ko",
                "images": [
                  {
                    "url": "https://i.scdn.co/image/ab67616d0000b273ce6d0eef0c1ce77e5f95bbbc",
                    "height": 640,
                    "width": 640
                  },
                  {
                    "url": "https://i.scdn.co/image/ab67616d00001e02ce6d0eef0c1ce77e5f95bbbc",
                    "height": 300,
                    "width": 300
                  },
                  {
                    "url": "https://i.scdn.co/image/ab67616d00004851ce6d0eef0c1ce77e5f95bbbc",
                    "height": 64,
                    "width": 64
                  }
                ],
                "name": "Progressive Psy Trance Picks Vol.8",
                "release_date": "2012-04-02",
                "release_date_precision": "day",
                "type": "album",
                "uri": "spotify:album:2pANdqPvxInB0YvcDiw4ko",
                "artists": [
                  {
                    "external_urls": {
                      "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of"
                    },
                    "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of",
                    "id": "0LyfQWJT6nXafLPZqxe9Of",
                    "name": "Various Artists",
                    "type": "artist",
                    "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of"
                  }
                ]
              },
              "artists": [
                {
                  "external_urls": {
                    "spotify": "https://open.spotify.com/artist/6eSdhw46riw2OUHgMwR8B5"
                  },
                  "href": "https://api.spotify.com/v1/artists/6eSdhw46riw2OUHgMwR8B5",
                  "id": "6eSdhw46riw2OUHgMwR8B5",
                  "name": "Odiseo",
                  "type": "artist",
                  "uri": "spotify:artist:6eSdhw46riw2OUHgMwR8B5"
                }
              ],
              "available_markets": [],
              "disc_number": 1,
              "duration_ms": 376000,
              "explicit": false,
              "external_ids": {
                "isrc": "DEKC41200989"
              },
              "external_urls": {
                "spotify": "https://open.spotify.com/track/4rzfv0JLZfVhOhbSQ8o5jZ"
              },
              "href": "https://api.spotify.com/v1/tracks/4rzfv0JLZfVhOhbSQ8o5jZ",
              "id": "4rzfv0JLZfVhOhbSQ8o5jZ",
              "name": "Api",
              "popularity": 6,
              "preview_url": null,
              "track_number": 10,
              "type": "track",
              "uri": "spotify:track:4rzfv0JLZfVhOhbSQ8o5jZ",
              "is_local": false,
              "episode": false,
              "track": true
            },
            "track": {
              "album": {
                "album_type": "compilation",
                "total_tracks": 20,
                "available_markets": [],
                "external_urls": {
                  "spotify": "https://open.spotify.com/album/2pANdqPvxInB0YvcDiw4ko"
                },
                "href": "https://api.spotify.com/v1/albums/2pANdqPvxInB0YvcDiw4ko",
                "id": "2pANdqPvxInB0YvcDiw4ko",
                "images": [
                  {
                    "url": "https://i.scdn.co/image/ab67616d0000b273ce6d0eef0c1ce77e5f95bbbc",
                    "height": 640,
                    "width": 640
                  },
                  {
                    "url": "https://i.scdn.co/image/ab67616d00001e02ce6d0eef0c1ce77e5f95bbbc",
                    "height": 300,
                    "width": 300
                  },
                  {
                    "url": "https://i.scdn.co/image/ab67616d00004851ce6d0eef0c1ce77e5f95bbbc",
                    "height": 64,
                    "width": 64
                  }
                ],
                "name": "Progressive Psy Trance Picks Vol.8",
                "release_date": "2012-04-02",
                "release_date_precision": "day",
                "type": "album",
                "uri": "spotify:album:2pANdqPvxInB0YvcDiw4ko",
                "artists": [
                  {
                    "external_urls": {
                      "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of"
                    },
                    "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of",
                    "id": "0LyfQWJT6nXafLPZqxe9Of",
                    "name": "Various Artists",
                    "type": "artist",
                    "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of"
                  }
                ]
              },
              "artists": [
                {
                  "external_urls": {
                    "spotify": "https://open.spotify.com/artist/6eSdhw46riw2OUHgMwR8B5"
                  },
                  "href": "https://api.spotify.com/v1/artists/6eSdhw46riw2OUHgMwR8B5",
                  "id": "6eSdhw46riw2OUHgMwR8B5",
                  "name": "Odiseo",
                  "type": "artist",
                  "uri": "spotify:artist:6eSdhw46riw2OUHgMwR8B5"
                }
              ],
              "available_markets": [],
              "disc_number": 1,
              "duration_ms": 376000,
              "explicit": false,
              "external_ids": {
                "isrc": "DEKC41200989"
              },
              "external_urls": {
                "spotify": "https://open.spotify.com/track/4rzfv0JLZfVhOhbSQ8o5jZ"
              },
              "href": "https://api.spotify.com/v1/tracks/4rzfv0JLZfVhOhbSQ8o5jZ",
              "id": "4rzfv0JLZfVhOhbSQ8o5jZ",
              "name": "Api",
              "popularity": 6,
              "preview_url": null,
              "track_number": 10,
              "type": "track",
              "uri": "spotify:track:4rzfv0JLZfVhOhbSQ8o5jZ",
              "is_local": false,
              "episode": false,
              "track": true
            },
            "primary_color": null,
            "video_thumbnail": {
              "url": null
            }
          }
        ]
      },
      "type": "playlist",
      "uri": "spotify:playlist:3cEYpjA9oz9GiPac4AsH4n",
      "followers": {
        "href": null,
        "total": 1475
      },
      "primary_color": null
    }
    "#;
    let full_playlist: FullPlaylist = deserialize(json);
    assert_eq!(full_playlist.items.total, 5);
    assert_eq!(
        full_playlist.items.href,
        "https://api.spotify.com/v1/playlists/3cEYpjA9oz9GiPac4AsH4n/items?offset=0&limit=100&locale=en-US,en;q%3D0.9"
    );
    #[allow(deprecated)]
    {
        assert_eq!(full_playlist.tracks.total, 5);
        assert_eq!(full_playlist.tracks.href, full_playlist.items.href);
    }
}

#[test]
#[wasm_bindgen_test]
fn test_audio_features() {
    let json = r#"
    {
        "duration_ms" : 255349,
        "key" : 5,
        "mode" : 0,
        "time_signature" : 4,
        "acousticness" : 0.514,
        "danceability" : 0.735,
        "energy" : 0.578,
        "instrumentalness" : 0.0902,
        "liveness" : 0.159,
        "loudness" : -11.840,
        "speechiness" : 0.0461,
        "valence" : 0.624,
        "tempo" : 98.002,
        "id" : "06AKEBrKUckW0KREUWRnvT",
        "uri" : "spotify:track:06AKEBrKUckW0KREUWRnvT",
        "track_href" : "https://api.spotify.com/v1/tracks/06AKEBrKUckW0KREUWRnvT",
        "analysis_url" : "https://api.spotify.com/v1/audio-analysis/06AKEBrKUckW0KREUWRnvT",
        "type" : "audio_features"
    }
    "#;
    let audio_features: AudioFeatures = deserialize(json);
    let duration = Duration::try_milliseconds(255349).unwrap();
    assert_eq!(audio_features.duration, duration);
}

#[test]
#[wasm_bindgen_test]
fn test_full_track() {
    let json = r#"
    {
  "album": {
    "album_type": "single",
    "artists": [
      {
        "external_urls": {
          "spotify": "https://open.spotify.com/artist/6sFIWsNpZYqfjUpaCgueju"
        },
        "href": "https://api.spotify.com/v1/artists/6sFIWsNpZYqfjUpaCgueju",
        "id": "6sFIWsNpZYqfjUpaCgueju",
        "name": "Carly Rae Jepsen",
        "type": "artist",
        "uri": "spotify:artist:6sFIWsNpZYqfjUpaCgueju"
      }
    ],
    "available_markets": [
      "ZA"
    ],
    "external_urls": {
      "spotify": "https://open.spotify.com/album/0tGPJ0bkWOUmH7MEOR77qc"
    },
    "href": "https://api.spotify.com/v1/albums/0tGPJ0bkWOUmH7MEOR77qc",
    "id": "0tGPJ0bkWOUmH7MEOR77qc",
    "images": [
      {
        "height": 64,
        "url": "https://i.scdn.co/image/5a73a056d0af707b4119a883d87285feda543fbb",
        "width": 64
      }
    ],
    "name": "Cut To The Feeling",
    "release_date": "2017-05-26",
    "release_date_precision": "day",
    "type": "album",
    "uri": "spotify:album:0tGPJ0bkWOUmH7MEOR77qc"
  },
  "artists": [
    {
      "external_urls": {
        "spotify": "https://open.spotify.com/artist/6sFIWsNpZYqfjUpaCgueju"
      },
      "href": "https://api.spotify.com/v1/artists/6sFIWsNpZYqfjUpaCgueju",
      "id": "6sFIWsNpZYqfjUpaCgueju",
      "name": "Carly Rae Jepsen",
      "type": "artist",
      "uri": "spotify:artist:6sFIWsNpZYqfjUpaCgueju"
    }
  ],
  "available_markets": [
    "ZA"
  ],
  "disc_number": 1,
  "duration_ms": 207959,
  "explicit": false,
  "external_ids": {
    "isrc": "USUM71703861"
  },
  "external_urls": {
    "spotify": "https://open.spotify.com/track/11dFghVXANMlKmJXsNCbNl"
  },
  "href": "https://api.spotify.com/v1/tracks/11dFghVXANMlKmJXsNCbNl",
  "id": "11dFghVXANMlKmJXsNCbNl",
  "is_local": false,
  "name": "Cut To The Feeling",
  "popularity": 63,
  "preview_url": "https://p.scdn.co/mp3-preview/3eb16018c2a700240e9dfb8817b6f2d041f15eb1?cid=774b29d4f13844c495f206cafdad9c86",
  "track_number": 1,
  "type": "track",
  "uri": "spotify:track:11dFghVXANMlKmJXsNCbNl"
}
    "#;
    let full_track: FullTrack = deserialize(json);
    let duration = Duration::try_milliseconds(207959).unwrap();
    assert_eq!(full_track.duration, duration);
}

#[test]
#[wasm_bindgen_test]
fn test_resume_point() {
    let json = r#"
    {
        "fully_played": false,
        "resume_position_ms": 423432
    }
    "#;
    let resume_point: ResumePoint = deserialize(json);
    let duration = Duration::try_milliseconds(423432).unwrap();
    assert_eq!(resume_point.resume_position, duration);
}

#[test]
#[wasm_bindgen_test]
fn test_resume_point_negative() {
    let json = r#"
    {
        "fully_played": true,
        "resume_position_ms": -1000
    }
    "#;
    let resume_point: ResumePoint = deserialize(json);
    let duration = Duration::try_milliseconds(-1000).unwrap();
    assert_eq!(resume_point.resume_position, duration);
}

#[test]
#[wasm_bindgen_test]
fn test_currently_playing_context() {
    let json = r#"
{
  "timestamp": 1607769168429,
  "context": {
    "external_urls": {
      "spotify": "https://open.spotify.com/album/2lgOc40hhHqjUGAKMWqGxO"
    },
    "href": "https://api.spotify.com/v1/albums/2lgOc40hhHqjUGAKMWqGxO",
    "type": "album",
    "uri": "spotify:album:2lgOc40hhHqjUGAKMWqGxO"
  },
  "progress_ms": 22270,
  "item": {
    "album": {
      "album_type": "single",
      "artists": [
        {
          "external_urls": {
            "spotify": "https://open.spotify.com/artist/0cGUm45nv7Z6M6qdXYQGTX"
          },
          "href": "https://api.spotify.com/v1/artists/0cGUm45nv7Z6M6qdXYQGTX",
          "id": "0cGUm45nv7Z6M6qdXYQGTX",
          "name": "Kehlani",
          "type": "artist",
          "uri": "spotify:artist:0cGUm45nv7Z6M6qdXYQGTX"
        }
      ],
      "external_urls": {
        "spotify": "https://open.spotify.com/album/2lgOc40hhHqjUGAKMWqGxO"
      },
      "href": "https://api.spotify.com/v1/albums/2lgOc40hhHqjUGAKMWqGxO",
      "id": "2lgOc40hhHqjUGAKMWqGxO",
      "images": [
        {
          "height": 64,
          "url": "https://i.scdn.co/image/ab67616d00004851fa7b2b60e85950ee93dcdc04",
          "width": 64
        }
      ],
      "name": "Playinwitme (feat. Kehlani)",
      "release_date": "2018-03-20",
      "release_date_precision": "day",
      "total_tracks": 1,
      "type": "album",
      "uri": "spotify:album:2lgOc40hhHqjUGAKMWqGxO"
    },
    "artists": [
      {
        "external_urls": {
          "spotify": "https://open.spotify.com/artist/0cGUm45nv7Z6M6qdXYQGTX"
        },
        "href": "https://api.spotify.com/v1/artists/0cGUm45nv7Z6M6qdXYQGTX",
        "id": "0cGUm45nv7Z6M6qdXYQGTX",
        "name": "Kehlani",
        "type": "artist",
        "uri": "spotify:artist:0cGUm45nv7Z6M6qdXYQGTX"
      }
    ],
    "available_markets": [],
    "disc_number": 1,
    "duration_ms": 191680,
    "explicit": false,
    "external_ids": {
      "isrc": "USAT21801141"
    },
    "external_urls": {
      "spotify": "https://open.spotify.com/track/4F1yvJfQ7gJkrcgFJQDjOr"
    },
    "href": "https://api.spotify.com/v1/tracks/4F1yvJfQ7gJkrcgFJQDjOr",
    "id": "4F1yvJfQ7gJkrcgFJQDjOr",
    "is_local": false,
    "is_playable": true,
    "linked_from": {
      "external_urls": {
        "spotify": "https://open.spotify.com/track/43cFjTTCD9Cni4aSL0sORz"
      },
      "href": "https://api.spotify.com/v1/tracks/43cFjTTCD9Cni4aSL0sORz",
      "id": "43cFjTTCD9Cni4aSL0sORz",
      "type": "track",
      "uri": "spotify:track:43cFjTTCD9Cni4aSL0sORz"
    },
    "name": "Playinwitme (feat. Kehlani)",
    "popularity": 70,
    "preview_url": "https://p.scdn.co/mp3-preview/05e8881d5c896a8d147d2e79150fb5480a4fb186?cid=774b29d4f13844c495f206cafdad9c86",
    "track_number": 9,
    "type": "track",
    "uri": "spotify:track:4F1yvJfQ7gJkrcgFJQDjOr"
  },
  "currently_playing_type": "track",
  "actions": {
    "disallows": {
      "resuming": true,
      "skipping_prev": true
    }
  },
  "is_playing": true
}
    "#;
    let currently_playing_context: CurrentlyPlayingContext = deserialize(json);
    let timestamp = 1607769168429;
    let second: i64 = (timestamp - timestamp % 1000) / 1000;
    let nanosecond = (timestamp % 1000) * 1000000;
    let dt = DateTime::from_timestamp(second, nanosecond as u32).unwrap();
    assert_eq!(currently_playing_context.timestamp, dt);

    let duration = Duration::try_milliseconds(22270).unwrap();
    assert_eq!(currently_playing_context.progress, Some(duration));
}

#[test]
#[wasm_bindgen_test]
fn test_current_playback_context() {
    let json = r#"
{
  "device": {
    "id": "28d0f845293d03a2713392905c6d30b6442719b5",
    "is_active": true,
    "is_private_session": false,
    "is_restricted": false,
    "name": "Web Player (Firefox)",
    "type": "Computer",
    "volume_percent": 100
  },
  "shuffle_state": false,
  "repeat_state": "off",
  "timestamp": 1607774342714,
  "context": {
    "external_urls": {
      "spotify": "https://open.spotify.com/album/2lgOc40hhHqjUGAKMWqGxO"
    },
    "href": "https://api.spotify.com/v1/albums/2lgOc40hhHqjUGAKMWqGxO",
    "type": "album",
    "uri": "spotify:album:2lgOc40hhHqjUGAKMWqGxO"
  },
  "item": {
    "album": {
      "album_type": "single",
      "artists": [
        {
          "external_urls": {
            "spotify": "https://open.spotify.com/artist/0cGUm45nv7Z6M6qdXYQGTX"
          },
          "href": "https://api.spotify.com/v1/artists/0cGUm45nv7Z6M6qdXYQGTX",
          "id": "0cGUm45nv7Z6M6qdXYQGTX",
          "name": "Kehlani",
          "type": "artist",
          "uri": "spotify:artist:0cGUm45nv7Z6M6qdXYQGTX"
        }
      ],
      "available_markets": [],
      "external_urls": {
        "spotify": "https://open.spotify.com/album/2lgOc40hhHqjUGAKMWqGxO"
      },
      "href": "https://api.spotify.com/v1/albums/2lgOc40hhHqjUGAKMWqGxO",
      "id": "2lgOc40hhHqjUGAKMWqGxO",
      "images": [
        {
          "height": 64,
          "url": "https://i.scdn.co/image/ab67616d00004851fa7b2b60e85950ee93dcdc04",
          "width": 64
        }
      ],
      "name": "Playinwitme (feat. Kehlani)",
      "release_date": "2018-03-20",
      "release_date_precision": "day",
      "total_tracks": 1,
      "type": "album",
      "uri": "spotify:album:2lgOc40hhHqjUGAKMWqGxO"
    },
    "artists": [
      {
        "external_urls": {
          "spotify": "https://open.spotify.com/artist/0cGUm45nv7Z6M6qdXYQGTX"
        },
        "href": "https://api.spotify.com/v1/artists/0cGUm45nv7Z6M6qdXYQGTX",
        "id": "0cGUm45nv7Z6M6qdXYQGTX",
        "name": "Kehlani",
        "type": "artist",
        "uri": "spotify:artist:0cGUm45nv7Z6M6qdXYQGTX"
      }
    ],
    "available_markets": [],
    "disc_number": 1,
    "duration_ms": 193093,
    "explicit": false,
    "external_ids": {
      "isrc": "USAT21801141"
    },
    "external_urls": {
      "spotify": "https://open.spotify.com/track/43cFjTTCD9Cni4aSL0sORz"
    },
    "href": "https://api.spotify.com/v1/tracks/43cFjTTCD9Cni4aSL0sORz",
    "id": "43cFjTTCD9Cni4aSL0sORz",
    "is_local": false,
    "name": "Playinwitme (feat. Kehlani)",
    "popularity": 0,
    "preview_url": null,
    "track_number": 1,
    "type": "track",
    "uri": "spotify:track:43cFjTTCD9Cni4aSL0sORz"
  },
  "currently_playing_type": "track",
  "actions": {
    "disallows": {
      "resuming": true,
      "skipping_prev": true
    }
  },
  "is_playing": true
}
    "#;
    let current_playback_context: CurrentPlaybackContext = deserialize(json);
    let timestamp = 1607774342714;
    let second: i64 = (timestamp - timestamp % 1000) / 1000;
    let nanosecond = (timestamp % 1000) * 1000000;
    let dt = DateTime::from_timestamp(second, nanosecond as u32).unwrap();
    assert_eq!(current_playback_context.timestamp, dt);
    assert!(current_playback_context.progress.is_none());
}

#[test]
#[wasm_bindgen_test]
fn test_current_user_queue() {
    let json = r#"
  {
    "currently_playing": {
      "album": {
        "album_type": "album",
        "artists": [
          {
            "external_urls": {
              "spotify": "https://open.spotify.com/artist/3DmG65yHQsMms7WAvrZOdt"
            },
            "href": "https://api.spotify.com/v1/artists/3DmG65yHQsMms7WAvrZOdt",
            "id": "3DmG65yHQsMms7WAvrZOdt",
            "name": "Enigma",
            "type": "artist",
            "uri": "spotify:artist:3DmG65yHQsMms7WAvrZOdt"
          }
        ],
        "available_markets": [
          "AD",
          "AE"
        ],
        "external_urls": {
          "spotify": "https://open.spotify.com/album/1t4hf9yHMQBoTz2CxTBJKj"
        },
        "href": "https://api.spotify.com/v1/albums/1t4hf9yHMQBoTz2CxTBJKj",
        "id": "1t4hf9yHMQBoTz2CxTBJKj",
        "images": [
          {
            "height": 640,
            "url": "https://i.scdn.co/image/ab67616d0000b2736d7e526534a3561be5e94a85",
            "width": 640
          },
          {
            "height": 300,
            "url": "https://i.scdn.co/image/ab67616d00001e026d7e526534a3561be5e94a85",
            "width": 300
          },
          {
            "height": 64,
            "url": "https://i.scdn.co/image/ab67616d000048516d7e526534a3561be5e94a85",
            "width": 64
          }
        ],
        "name": "The Cross Of Changes",
        "release_date": "1993-01-01",
        "release_date_precision": "day",
        "total_tracks": 9,
        "type": "album",
        "uri": "spotify:album:1t4hf9yHMQBoTz2CxTBJKj"
      },
      "artists": [
        {
          "external_urls": {
            "spotify": "https://open.spotify.com/artist/3DmG65yHQsMms7WAvrZOdt"
          },
          "href": "https://api.spotify.com/v1/artists/3DmG65yHQsMms7WAvrZOdt",
          "id": "3DmG65yHQsMms7WAvrZOdt",
          "name": "Enigma",
          "type": "artist",
          "uri": "spotify:artist:3DmG65yHQsMms7WAvrZOdt"
        }
      ],
      "available_markets": [
        "AD",
        "AE"
      ],
      "disc_number": 1,
      "duration_ms": 532560,
      "explicit": false,
      "external_ids": {
        "isrc": "DEG129300014"
      },
      "external_urls": {
        "spotify": "https://open.spotify.com/track/3E61ra5VUF6eu3tpfsXfou"
      },
      "href": "https://api.spotify.com/v1/tracks/3E61ra5VUF6eu3tpfsXfou",
      "id": "3E61ra5VUF6eu3tpfsXfou",
      "is_local": false,
      "name": "I Love You... I'll Kill You",
      "popularity": 48,
      "preview_url": "https://p.scdn.co/mp3-preview/221a5d1c44ffdc0452f65a56adfd95c92b61a989?cid=774b29d4f13844c495f206cafdad9c86",
      "track_number": 4,
      "type": "track",
      "uri": "spotify:track:3E61ra5VUF6eu3tpfsXfou"
    },
    "queue": [
      {
        "album": {
          "album_type": "compilation",
          "artists": [
            {
              "external_urls": {
                "spotify": "https://open.spotify.com/artist/0LyfQWJT6nXafLPZqxe9Of"
              },
              "href": "https://api.spotify.com/v1/artists/0LyfQWJT6nXafLPZqxe9Of",
              "id": "0LyfQWJT6nXafLPZqxe9Of",
              "name": "Various Artists",
              "type": "artist",
              "uri": "spotify:artist:0LyfQWJT6nXafLPZqxe9Of"
            }
          ],
          "available_markets": [
            "AD",
            "AE"
          ],
          "external_urls": {
            "spotify": "https://open.spotify.com/album/6IV7472Hni7A1ENilCManS"
          },
          "href": "https://api.spotify.com/v1/albums/6IV7472Hni7A1ENilCManS",
          "id": "6IV7472Hni7A1ENilCManS",
          "images": [
            {
              "height": 640,
              "url": "https://i.scdn.co/image/ab67616d0000b273afda2a51e7bb55197fdeb4c0",
              "width": 640
            },
            {
              "height": 300,
              "url": "https://i.scdn.co/image/ab67616d00001e02afda2a51e7bb55197fdeb4c0",
              "width": 300
            },
            {
              "height": 64,
              "url": "https://i.scdn.co/image/ab67616d00004851afda2a51e7bb55197fdeb4c0",
              "width": 64
            }
          ],
          "name": "The Grand Budapest Hotel (Original Soundtrack)",
          "release_date": "2014-01-01",
          "release_date_precision": "day",
          "total_tracks": 32,
          "type": "album",
          "uri": "spotify:album:6IV7472Hni7A1ENilCManS"
        },
        "artists": [
          {
            "external_urls": {
              "spotify": "https://open.spotify.com/artist/71jzN72g8qWMCMkWC5p1Z0"
            },
            "href": "https://api.spotify.com/v1/artists/71jzN72g8qWMCMkWC5p1Z0",
            "id": "71jzN72g8qWMCMkWC5p1Z0",
            "name": "Alexandre Desplat",
            "type": "artist",
            "uri": "spotify:artist:71jzN72g8qWMCMkWC5p1Z0"
          }
        ],
        "available_markets": [
          "AD",
          "AE"
        ],
        "disc_number": 1,
        "duration_ms": 335026,
        "explicit": false,
        "external_ids": {
          "isrc": "USA171491023"
        },
        "external_urls": {
          "spotify": "https://open.spotify.com/track/1w3bpz8NvESU3A2jd9e22a"
        },
        "href": "https://api.spotify.com/v1/tracks/1w3bpz8NvESU3A2jd9e22a",
        "id": "1w3bpz8NvESU3A2jd9e22a",
        "is_local": false,
        "name": "Canto At Gabelmeister's Peak",
        "popularity": 40,
        "preview_url": "https://p.scdn.co/mp3-preview/a2008fb3fe62cfe09b2c80f99236bdcdaab55c79?cid=774b29d4f13844c495f206cafdad9c86",
        "track_number": 27,
        "type": "track",
        "uri": "spotify:track:1w3bpz8NvESU3A2jd9e22a"
      }
    ]
  }
  "#;
    let current_user_queue: CurrentUserQueue = deserialize(json);
    assert_eq!(
        current_user_queue
            .currently_playing
            .unwrap()
            .id()
            .unwrap()
            .id(),
        "3E61ra5VUF6eu3tpfsXfou"
    );
    assert_eq!(current_user_queue.queue.len(), 1);
    assert_eq!(
        current_user_queue.queue[0].id().unwrap().id(),
        "1w3bpz8NvESU3A2jd9e22a"
    );
}

#[test]
#[wasm_bindgen_test]
fn test_audio_analysis_track() {
    let json = r#"
  {
    "num_samples": 5630445,
    "duration": 255.34898,
    "sample_md5": "",
    "offset_seconds": 0,
    "window_seconds": 0,
    "analysis_sample_rate": 22050,
    "analysis_channels": 1,
    "end_of_fade_in": 0,
    "start_of_fade_out": 251.73334,
    "loudness": -11.84,
    "tempo": 98.002,
    "tempo_confidence": 0.423,
    "time_signature": 4,
    "time_signature_confidence": 1,
    "key": 5,
    "key_confidence": 0.36,
    "mode": 0,
    "mode_confidence": 0.414,
    "codestring": "e",
    "code_version": 3.15,
    "echoprintstring": "e",
    "echoprint_version": 4.12,
    "synchstring": "eJ",
    "synch_version": 1,
    "rhythmstring": "e",
    "rhythm_version": 1
  }
  "#;
    let audio_analysis_track: AudioAnalysisTrack = deserialize(json);
    assert_eq!(audio_analysis_track.mode, Modality::Minor);
}

#[test]
#[wasm_bindgen_test]
fn test_simplified_playlist() {
    let json = r#"
  {
    "collaborative": false,
    "description": "Chegou o grande dia, aperte o play e partiu fim de semana!",
    "external_urls": {
      "spotify": "https://open.spotify.com/playlist/37i9dQZF1DX8mBRYewE6or"
    },
    "href": "https://api.spotify.com/v1/playlists/37i9dQZF1DX8mBRYewE6or",
    "id": "37i9dQZF1DX8mBRYewE6or",
    "images": [
      {
        "height": null,
        "url": "https://i.scdn.co/image/ab67706f00000003206a95fa5badbe1d33b65e14",
        "width": null
      }
    ],
    "name": "Sexta",
    "owner": {
      "display_name": "Spotify",
      "external_urls": {
        "spotify": "https://open.spotify.com/user/spotify"
      },
      "href": "https://api.spotify.com/v1/users/spotify",
      "id": "spotify",
      "type": "user",
      "uri": "spotify:user:spotify"
    },
    "primary_color": null,
    "public": null,
    "snapshot_id": "MTYxMzM5MzIyMywwMDAwMDAwMGQ0MWQ4Y2Q5OGYwMGIyMDRlOTgwMDk5OGVjZjg0Mjdl",
    "tracks": {
      "href": "https://api.spotify.com/v1/playlists/37i9dQZF1DX8mBRYewE6or/tracks",
      "total": 62
    },
    "type": "playlist",
    "uri": "spotify:playlist:37i9dQZF1DX8mBRYewE6or"
  }
  "#;
    let simplified_playlist: SimplifiedPlaylist = deserialize(json);
    assert_eq!(
        simplified_playlist.items.href,
        "https://api.spotify.com/v1/playlists/37i9dQZF1DX8mBRYewE6or/tracks"
    );
    assert_eq!(simplified_playlist.items.total, 62);
}

#[test]
#[wasm_bindgen_test]
fn test_collectionyourepisodes_type() {
    let json = r#"
{
	"external_urls": {
		"spotify": "https://open.spotify.com/collection/episodes"
	},
	"href": "https://api.spotify.com/v1/me/episodes",
	"type": "collectionyourepisodes",
	"uri": "spotify:user:<username>:collection:your-episodes"
}
"#;
    let context: Context = deserialize(json);
    assert_eq!(context._type, Type::Collectionyourepisodes);
}

#[test]
#[wasm_bindgen_test]
fn test_fallback_variant_type_to_capture_new_type() {
    let json = r#"
{
	"external_urls": {
		"spotify": "https://open.spotify.com/collection/episodes"
	},
	"href": "https://api.spotify.com/v1/me/episodes",
	"type": "onlygodknow",
	"uri": "spotify:user:<username>:collection:your-episodes"
}
"#;
    let context: Context = deserialize(json);
    assert_eq!(context._type, Type::Unknown("onlygodknow".to_string()));
}

#[test]
#[wasm_bindgen_test]
fn test_null_id_in_tracklink() {
    let json = r#"
{
          "external_urls": {
            "spotify": "https://open.spotify.com/track/0tSkMuKKrLXEfxc58cEhFX"
          },
          "href": "https://api.spotify.com/v1/tracks/0tSkMuKKrLXEfxc58cEhFX",
          "id": null,
          "type": "track",
          "uri": "spotify:track:0tSkMuKKrLXEfxc58cEhFX"
        }
"#;
    let linked_from: TrackLink = deserialize(json);
    assert!(linked_from.id.is_none());
    assert_eq!(linked_from.r#type, Type::Track);
}

#[test]
#[wasm_bindgen_test]
fn test_null_item_in_page() {
    let json = r#"
{
  "href": "https://api.spotify.com/v1/search?offset=17&limit=2&query=My%20Playlist&type=playlist&market=FR",
  "items": [
    null
  ],
  "limit": 20,
  "next": null,
  "offset": 0,
  "previous": null,
  "total": 1
}"#;
    let page: Page<SimplifiedPlaylist> = deserialize(json);
    assert_eq!(page.items.len(), 0);
    assert_eq!(page.total, 1); // Because one element is null so ignored at deserialization but counted in total
    assert_eq!(page.limit, 20);
    assert!(page.next.is_none());
    assert!(page.previous.is_none());
}

#[test]
#[wasm_bindgen_test]
fn test_deserialization_playlist_item_with_malformed_episodes() {
    // To fix https://github.com/ramsayleung/rspotify/issues/525
    let json = r#"
{
  "href": "https://api.spotify.com/v1/playlists/4MAcblnU4nwtIZ267YI24a/tracks?offset=0&limit=100",
  "items": [
    {
      "added_at": "2024-12-14T13:23:53Z",
      "added_by": {
        "external_urls": {
          "spotify": "https://open.spotify.com/user/31rhaare4k4nkr5bngqyiiz4bq6a"
        },
        "href": "https://api.spotify.com/v1/users/31rhaare4k4nkr5bngqyiiz4bq6a",
        "id": "31rhaare4k4nkr5bngqyiiz4bq6a",
        "type": "user",
        "uri": "spotify:user:31rhaare4k4nkr5bngqyiiz4bq6a"
      },
      "is_local": false,
      "primary_color": null,
      "track": {
        "preview_url": "https://podz-content.spotifycdn.com/audio/clips/3pEQnFvjtRVnJURokrIEaH/clip_46844_106844.mp3",
        "available_markets": ["AD"],
        "explicit": false,
        "type": "episode",
        "episode": false,
        "track": true,
        "album": {
          "available_markets": ["AD"],
          "type": "show",
          "album_type": "compilation",
          "href": "https://api.spotify.com/v1/shows/4C53FwIBO9tEhJ0dkMN3GN",
          "id": "4C53FwIBO9tEhJ0dkMN3GN",
          "images": [
            {
              "height": 64,
              "url": "https://i.scdn.co/image/ab6765630000f68dc5087ef7f8e3caa4fd6e6bcd",
              "width": 64
            }
          ],
          "name": "REALPODCASTNOTMUSIC123",
          "release_date": null,
          "release_date_precision": null,
          "uri": "spotify:show:4C53FwIBO9tEhJ0dkMN3GN",
          "artists": [
            {
              "external_urls": {
                "spotify": "https://open.spotify.com/show/4C53FwIBO9tEhJ0dkMN3GN"
              },
              "href": "https://api.spotify.com/v1/shows/4C53FwIBO9tEhJ0dkMN3GN",
              "id": "4C53FwIBO9tEhJ0dkMN3GN",
              "name": null,
              "type": "REALPODCASTNOTMUSIC123",
              "uri": "spotify:show:4C53FwIBO9tEhJ0dkMN3GN"
            }
          ],
          "external_urls": {
            "spotify": "https://open.spotify.com/album/4C53FwIBO9tEhJ0dkMN3GN"
          },
          "total_tracks": 1
        },
        "artists": [
          {
            "external_urls": {
              "spotify": "https://open.spotify.com/show/4C53FwIBO9tEhJ0dkMN3GN"
            },
            "href": "https://api.spotify.com/v1/shows/4C53FwIBO9tEhJ0dkMN3GN",
            "id": "4C53FwIBO9tEhJ0dkMN3GN",
            "name": null,
            "type": "REALPODCASTNOTMUSIC123",
            "uri": "spotify:show:4C53FwIBO9tEhJ0dkMN3GN"
          }
        ],
        "disc_number": 0,
        "track_number": 0,
        "duration_ms": 119257,
        "external_ids": {
          "spotify": "https://open.spotify.com/episode/4IBGQd8aV4j6WGqGOjdJmE"
        },
        "external_urls": {
          "spotify": "https://open.spotify.com/episode/4IBGQd8aV4j6WGqGOjdJmE"
        },
        "href": "https://api.spotify.com/v1/episodes/4IBGQd8aV4j6WGqGOjdJmE",
        "id": "4IBGQd8aV4j6WGqGOjdJmE",
        "name": "ITS BEGINNING TO LOOK A LOT LIKE CHRISTMAS (Mac Demarco)",
        "popularity": 0,
        "uri": "spotify:episode:4IBGQd8aV4j6WGqGOjdJmE",
        "is_local": false
      },
      "video_thumbnail": {
        "url": null
      }
    }
  ],
  "limit": 100,
  "next": null,
  "offset": 0,
  "previous": null,
  "total": 1
}
"#;
    let page: Page<PlaylistItem> = deserialize(json);
    assert_eq!(page.total, 1);
    let item = page.items.first().unwrap().item.clone().unwrap();
    assert!(item.is_unknown());
    let id = item.id().unwrap();
    assert!(matches!(id, PlayableId::Episode(_)));
    assert_eq!(id.id(), "4IBGQd8aV4j6WGqGOjdJmE");
}
