//! Gitea API client for deploy key management.

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone)]
pub struct GiteaClient {
    api_url: String,
    token: String,
    owner: String,
    repo: String,
}

#[derive(Debug, Serialize)]
struct CreateKeyRequest<'a> {
    title: &'a str,
    key: &'a str,
    read_only: bool,
}

#[derive(Debug, Deserialize)]
pub struct DeployKey {
    pub id: u64,
    #[allow(dead_code)]
    pub title: String,
    #[allow(dead_code)]
    pub key: String,
}

impl GiteaClient {
    pub fn new(api_url: &str, token: &str, owner: &str, repo: &str) -> Self {
        Self {
            api_url: api_url.trim_end_matches('/').to_string(),
            token: token.to_string(),
            owner: owner.to_string(),
            repo: repo.to_string(),
        }
    }

    /// Create a deploy key, returning its ID.
    pub fn create_deploy_key(&self, title: &str, public_key: &str) -> Result<u64> {
        let url = format!(
            "{}/repos/{}/{}/keys",
            self.api_url, self.owner, self.repo
        );

        let client = reqwest::blocking::Client::new();
        let resp = client
            .post(&url)
            .header("Authorization", format!("token {}", self.token))
            .header("Content-Type", "application/json")
            .json(&CreateKeyRequest {
                title,
                key: public_key,
                read_only: false,
            })
            .send()
            .context("Gitea API request failed")?;

        if !resp.status().is_success() {
            let status = resp.status();
            let body = resp.text().unwrap_or_default();
            anyhow::bail!("Gitea API error {}: {}", status, body);
        }

        let key: DeployKey = resp.json().context("parse deploy key response")?;
        Ok(key.id)
    }

    /// Delete a deploy key by ID.
    pub fn delete_deploy_key(&self, key_id: u64) -> Result<()> {
        let url = format!(
            "{}/repos/{}/{}/keys/{}",
            self.api_url, self.owner, self.repo, key_id
        );

        let client = reqwest::blocking::Client::new();
        let resp = client
            .delete(&url)
            .header("Authorization", format!("token {}", self.token))
            .send()
            .context("Gitea API request failed")?;

        if !resp.status().is_success() && resp.status().as_u16() != 404 {
            let status = resp.status();
            let body = resp.text().unwrap_or_default();
            anyhow::bail!("Gitea API error {}: {}", status, body);
        }

        Ok(())
    }

    /// List all deploy keys.
    #[allow(dead_code)]
    pub fn list_deploy_keys(&self) -> Result<Vec<DeployKey>> {
        let url = format!(
            "{}/repos/{}/{}/keys",
            self.api_url, self.owner, self.repo
        );

        let client = reqwest::blocking::Client::new();
        let resp = client
            .get(&url)
            .header("Authorization", format!("token {}", self.token))
            .send()
            .context("Gitea API request failed")?;

        if !resp.status().is_success() {
            let status = resp.status();
            let body = resp.text().unwrap_or_default();
            anyhow::bail!("Gitea API error {}: {}", status, body);
        }

        let keys: Vec<DeployKey> = resp.json().context("parse deploy keys response")?;
        Ok(keys)
    }
}
