use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Clone)]
pub struct Config {
    pub public_token: String,
    pub base_url: String,
    pub traits: HashMap<String, String>,
}

impl Config {
    pub fn new(public_token: impl Into<String>) -> Self {
        Config {
            public_token: public_token.into(),
            base_url: "https://flags.deployramp.com".to_string(),
            traits: HashMap::new(),
        }
    }

    pub fn base_url(mut self, url: impl Into<String>) -> Self {
        self.base_url = url.into();
        self
    }

    pub fn traits(mut self, traits: HashMap<String, String>) -> Self {
        self.traits = traits;
        self
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraitCondition {
    #[serde(rename = "type")]
    pub condition_type: String,
    #[serde(rename = "traitKey", skip_serializing_if = "Option::is_none")]
    pub trait_key: Option<String>,
    #[serde(rename = "traitValue", skip_serializing_if = "Option::is_none")]
    pub trait_value: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub conditions: Option<Vec<TraitCondition>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FlagSegment {
    #[serde(rename = "segmentId")]
    pub segment_id: String,
    pub condition: TraitCondition,
    #[serde(rename = "rolloutPercentage")]
    pub rollout_percentage: i32,
    pub sticky: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FlagData {
    pub name: String,
    pub enabled: bool,
    #[serde(rename = "rolloutPercentage")]
    pub rollout_percentage: i32,
    pub value: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub segments: Option<Vec<FlagSegment>>,
    #[serde(rename = "stickyAssignments", skip_serializing_if = "Option::is_none")]
    pub sticky_assignments: Option<Vec<String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EvaluationEvent {
    #[serde(rename = "type")]
    pub event_type: String,
    #[serde(rename = "flagName")]
    pub flag_name: String,
    pub result: bool,
    pub traits: HashMap<String, String>,
    #[serde(rename = "userId")]
    pub user_id: String,
    pub timestamp: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceEvent {
    #[serde(rename = "type")]
    pub event_type: String,
    #[serde(rename = "flagName")]
    pub flag_name: String,
    #[serde(rename = "durationMs")]
    pub duration_ms: f64,
    pub branch: String, // "enabled" or "disabled"
    pub traits: HashMap<String, String>,
    #[serde(rename = "userId")]
    pub user_id: String,
    pub timestamp: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct WsMessage {
    #[serde(rename = "type")]
    pub message_type: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub flags: Option<Vec<FlagData>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub evaluations: Option<Vec<EvaluationEvent>>,
    #[serde(rename = "performanceEvents", skip_serializing_if = "Option::is_none")]
    pub performance_events: Option<Vec<PerformanceEvent>>,
}

#[derive(Serialize)]
pub(crate) struct FetchFlagsRequest {
    #[serde(rename = "userId", skip_serializing_if = "Option::is_none")]
    pub user_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub traits: Option<HashMap<String, String>>,
}

#[derive(Deserialize)]
pub(crate) struct FetchFlagsResponse {
    pub flags: Vec<FlagData>,
}

#[derive(Serialize)]
pub(crate) struct ReportRequest {
    #[serde(rename = "flagName")]
    pub flag_name: String,
    pub message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub stack: Option<String>,
    #[serde(rename = "userId", skip_serializing_if = "Option::is_none")]
    pub user_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub traits: Option<HashMap<String, String>>,
}
