use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct User {
    pub id: String,
    pub username: String,
    pub full_name: Option<String>,
    pub biography: Option<String>,
    pub profile_pic_url: Option<String>,
    pub is_private: bool,
    pub is_verified: bool,
    pub follower_count: u64,
    pub following_count: u64,
    pub media_count: u64,
    pub external_url: Option<String>,
    pub business_email: Option<String>,
    pub business_phone: Option<String>,
    pub category: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Media {
    pub id: String,
    pub shortcode: String,
    pub media_type: MediaType,
    pub caption: Option<String>,
    pub timestamp: i64,
    pub like_count: u64,
    pub comment_count: u64,
    pub view_count: Option<u64>,
    pub play_count: Option<u64>,
    pub display_url: String,
    pub video_url: Option<String>,
    pub owner: MediaOwner,
    pub is_video: bool,
    pub tagged_users: Vec<TaggedUser>,
    pub location: Option<Location>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum MediaType {
    Image,
    Video,
    Reel,
    Carousel,
    Story,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MediaOwner {
    pub id: String,
    pub username: String,
    pub profile_pic_url: Option<String>,
    pub is_verified: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaggedUser {
    pub id: String,
    pub username: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Location {
    pub id: String,
    pub name: String,
    pub slug: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reel {
    pub id: String,
    pub shortcode: String,
    pub caption: Option<String>,
    pub timestamp: i64,
    pub like_count: u64,
    pub comment_count: u64,
    pub play_count: u64,
    pub view_count: u64,
    pub video_url: String,
    pub thumbnail_url: String,
    pub duration: f64,
    pub owner: MediaOwner,
    pub audio: Option<ReelAudio>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReelAudio {
    pub id: String,
    pub title: String,
    pub artist: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Comment {
    pub id: String,
    pub text: String,
    pub timestamp: i64,
    pub like_count: u64,
    pub owner: CommentOwner,
    pub replies: Vec<Comment>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommentOwner {
    pub id: String,
    pub username: String,
    pub profile_pic_url: Option<String>,
    pub is_verified: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Like {
    pub id: String,
    pub username: String,
    pub full_name: Option<String>,
    pub profile_pic_url: Option<String>,
    pub is_verified: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Story {
    pub id: String,
    pub media_type: MediaType,
    pub timestamp: i64,
    pub expiring_at: i64,
    pub display_url: String,
    pub video_url: Option<String>,
    pub owner: MediaOwner,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Highlight {
    pub id: String,
    pub title: String,
    pub cover_url: String,
    pub media_count: u64,
    pub items: Vec<Story>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SearchResult {
    pub users: Vec<UserSearchItem>,
    pub hashtags: Vec<HashtagSearchItem>,
    pub places: Vec<PlaceSearchItem>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserSearchItem {
    pub id: String,
    pub username: String,
    pub full_name: Option<String>,
    pub profile_pic_url: Option<String>,
    pub is_verified: bool,
    pub is_private: bool,
    pub follower_count: Option<u64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HashtagSearchItem {
    pub id: String,
    pub name: String,
    pub media_count: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlaceSearchItem {
    pub id: String,
    pub name: String,
    pub address: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Pagination<T> {
    pub items: Vec<T>,
    pub has_next: bool,
    pub cursor: Option<String>,
}

impl<T> Default for Pagination<T> {
    fn default() -> Self {
        Self {
            items: Vec::new(),
            has_next: false,
            cursor: None,
        }
    }
}
