use std::{collections::HashMap, env};

use serde_json::json;
use wreq::{Client, Proxy};
use wreq_util::Emulation;

#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct FlareSolverrRequest {
    pub cmd: String,
    pub url: String,
    pub maxTimeout: u32,
}

#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct FlaresolverrCookie {
    pub name: String,
    pub value: String,
    pub domain: String,
    pub path: String,
    pub expires: f64,
    pub size: u64,
    pub httpOnly: bool,
    pub secure: bool,
    pub session: bool,
    pub sameSite: Option<String>,
    pub priority: String,
    pub sameParty: bool,
    pub sourceScheme: String,
    pub sourcePort: u32,
    pub partitionKey: Option<String>,
}

#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct FlareSolverrSolution {
    pub url: String,
    pub status: u32,
    pub response: String,
    pub headers: HashMap<String, String>,
    pub cookies: Vec<FlaresolverrCookie>,
    pub userAgent: String,
}

#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct FlareSolverrResponse {
    pub status: String,
    pub message: String,
    pub solution: FlareSolverrSolution,
    pub startTimestamp: u64,
    pub endTimestamp: u64,
    pub version: String,
}

pub struct Flaresolverr {
    url: String,
    proxy: bool,
}

impl Flaresolverr {
    pub fn new(url: String) -> Self {
        Self { url, proxy: false }
    }

    pub fn set_proxy(&mut self, proxy: bool) {
        self.proxy = proxy;
    }

    pub async fn solve(
        &self,
        request: FlareSolverrRequest,
    ) -> Result<FlareSolverrResponse, Box<dyn std::error::Error>> {
        let client = Client::builder().emulation(Emulation::Firefox136).build()?;

        let mut req = client
            .post(&self.url)
            .header("Content-Type", "application/json")
            .json(&json!({
                "cmd": request.cmd,
                "url": request.url,
                "maxTimeout": request.maxTimeout,
            }));

        if self.proxy {
            if let Ok(proxy_url) = env::var("BURP_URL") {
                match Proxy::all(&proxy_url) {
                    Ok(proxy) => {
                        req = req.proxy(proxy);
                    }
                    Err(e) => {
                        eprintln!("Invalid proxy URL '{}': {}", proxy_url, e);
                    }
                }
            }
        }

        let response = req.send().await?;

        let body = response.json::<FlareSolverrResponse>().await?;
        Ok(body)
    }
}
