//! response.rs

use hyper::{Body, Response, StatusCode, header};
use mime_guess::from_path as get_mine_from_path;
use serde::Serialize;
use std::fs::read_to_string as read_file;

/// 转换为 HTTP 响应的 trait
pub trait IntoResponse {
	fn into_response(self) -> Response<Body>;
}

// 为 &str 实现
impl IntoResponse for &'static str {
	fn into_response(self) -> Response<Body> {
		Response::builder()
			.header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
			.body(Body::from(self))
			.unwrap()
	}
}

// 为 String 实现
impl IntoResponse for String {
	fn into_response(self) -> Response<Body> {
		Response::builder()
			.header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
			.body(Body::from(self))
			.unwrap()
	}
}

// 为 Vec<u8> 实现
impl IntoResponse for Vec<u8> {
	fn into_response(self) -> Response<Body> {
		Response::builder().body(Body::from(self)).unwrap()
	}
}

// 为 () 实现（空响应）
impl IntoResponse for () {
	fn into_response(self) -> Response<Body> {
		Response::builder()
			.status(StatusCode::NO_CONTENT)
			.body(Body::empty())
			.unwrap()
	}
}

// 为 StatusCode 实现（仅状态码）
impl IntoResponse for StatusCode {
	fn into_response(self) -> Response<Body> {
		Response::builder()
			.status(self)
			.body(Body::empty())
			.unwrap()
	}
}

/// JSON 响应包装器
pub struct Json<T: Serialize>(pub T);

impl<T: Serialize> IntoResponse for Json<T> {
	fn into_response(self) -> Response<Body> {
		let json = serde_json::to_string(&self.0).unwrap();
		Response::builder()
			.header(header::CONTENT_TYPE, "application/json")
			.body(Body::from(json))
			.unwrap()
	}
}

/// HTML 响应包装器
pub struct Html(pub String);

impl IntoResponse for Html {
	fn into_response(self) -> Response<Body> {
		Response::builder()
			.header(header::CONTENT_TYPE, "text/html; charset=utf-8")
			.body(Body::from(self.0))
			.unwrap()
	}
}

/// 文本响应包装器
pub struct Text(pub String);

impl IntoResponse for Text {
	fn into_response(self) -> Response<Body> {
		Response::builder()
			.header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
			.body(Body::from(self.0))
			.unwrap()
	}
}

// 为 Result 实现
impl<T, E> IntoResponse for Result<T, E>
where
	T: IntoResponse,
	E: IntoResponse,
{
	fn into_response(self) -> Response<Body> {
		match self {
			Ok(value) => value.into_response(),
			Err(err) => err.into_response(),
		}
	}
}

// 重定向url包装器
pub struct Redirect(pub String);

impl IntoResponse for Redirect {
	fn into_response(self) -> Response<Body> {
        Response::builder()
            .status(302)
            .header("Location", self.0)
            .body(Body::empty())
            .unwrap()
	}
}

// 永久重定向url包装器
pub struct PermRedirect(pub String);

impl IntoResponse for PermRedirect {
    fn into_response(self) -> Response<Body> {
        Response::builder()
            .status(301)
            .header("Location", self.0)
            .body(Body::empty())
            .unwrap()
    }
}

impl Redirect {
	pub fn perm(url: String) -> PermRedirect {
		PermRedirect(url)
	}
}

// 文件包装器
pub struct File(pub String, pub bool);

impl IntoResponse for File {
	fn into_response(self) -> Response<Body> {
		Response::builder()
			.header(
				header::CONTENT_TYPE,
				if self.1 {
					"application/octet-stream; charset=utf-8".to_string()
				} else {
					format!(
						"{}; charset=utf-8",
						get_mine_from_path(&self.0)
							.first_or_octet_stream()
							.to_string()
					)
				},
			)
			.body(Body::from(read_file(self.0).unwrap_or(String::new())))
			.unwrap()
	}
}
