mod support;

use crate::support::{Check, TestResult, common_tests};
use genai::adapter::AdapterKind;
use genai::chat::ReasoningEffort;
use genai::resolver::AuthData;

// "gemini-2.5-flash" "gemini-2.5-pro" "gemini-2.5-flash-lite"
// "gemini-2.5-flash-zero"
const MODEL_GPRO_3: &str = "gemini-3-pro-preview";
const MODEL_FLASH_3: &str = "gemini-3-flash-preview"; // pure gem, fast, cheap, and good!
const MODEL_FLASH_2_5: &str = "gemini-2.5-flash";
const MODEL_NS: &str = "gemini::gemini-2.5-flash";

// region:    --- Chat

#[tokio::test]
async fn test_chat_simple_ok() -> TestResult<()> {
	common_tests::common_test_chat_simple_ok(MODEL_FLASH_2_5, None).await
}

#[tokio::test]
async fn test_chat_reasoning_ok() -> TestResult<()> {
	common_tests::common_test_chat_reasoning_ok(
		MODEL_GPRO_3,
		ReasoningEffort::Low,
		Some(Check::REASONING_USAGE | Check::REASONING_USAGE),
	)
	.await
}

#[tokio::test]
async fn test_chat_namespaced_ok() -> TestResult<()> {
	common_tests::common_test_chat_simple_ok(MODEL_NS, None).await
}

#[tokio::test]
async fn test_chat_multi_system_ok() -> TestResult<()> {
	common_tests::common_test_chat_multi_system_ok(MODEL_FLASH_2_5).await
}

#[tokio::test]
async fn test_chat_json_structured_ok() -> TestResult<()> {
	common_tests::common_test_chat_json_structured_ok(MODEL_FLASH_2_5, Some(Check::USAGE)).await
}

#[tokio::test]
async fn test_chat_temperature_ok() -> TestResult<()> {
	common_tests::common_test_chat_temperature_ok(MODEL_FLASH_2_5).await
}

#[tokio::test]
async fn test_chat_stop_sequences_ok() -> TestResult<()> {
	common_tests::common_test_chat_stop_sequences_ok(MODEL_FLASH_2_5).await
}

// endregion: --- Chat

// region:    --- Chat Implicit Cache

// NOTE: This should eventually work with the 2.5 Flash, but right now, we do not get the cached_tokens
//       So, disabling
// #[tokio::test]
// async fn test_chat_cache_implicit_simple_ok() -> TestResult<()> {
// 	common_tests::common_test_chat_cache_implicit_simple_ok(MODEL).await
// }

// endregion: --- Chat Implicit Cache

// region:    --- Chat Stream Tests

#[tokio::test]
async fn test_chat_stream_simple_ok() -> TestResult<()> {
	common_tests::common_test_chat_stream_simple_ok(MODEL_FLASH_3, None).await
}

#[tokio::test]
async fn test_chat_stream_capture_content_ok() -> TestResult<()> {
	common_tests::common_test_chat_stream_capture_content_ok(MODEL_FLASH_3).await
}

#[tokio::test]
async fn test_chat_stream_capture_all_ok() -> TestResult<()> {
	common_tests::common_test_chat_stream_capture_all_ok(MODEL_FLASH_3, None).await
}

// endregion: --- Chat Stream Tests

// region:    --- Binary Tests

// NOTE: Gemini does not seem to support URL
// #[tokio::test]
// async fn test_chat_binary_image_url_ok() -> TestResult<()> {
// 	common_tests::common_test_chat_image_url_ok(MODEL).await
// }

#[tokio::test]
async fn test_chat_binary_image_b64_ok() -> TestResult<()> {
	common_tests::common_test_chat_image_b64_ok(MODEL_FLASH_2_5).await
}

#[tokio::test]
async fn test_chat_binary_pdf_b64_ok() -> TestResult<()> {
	common_tests::common_test_chat_pdf_b64_ok(MODEL_FLASH_2_5).await
}

#[tokio::test]
async fn test_chat_binary_image_file_ok() -> TestResult<()> {
	common_tests::common_test_chat_image_file_ok(MODEL_FLASH_2_5).await
}

#[tokio::test]
async fn test_chat_binary_multi_b64_ok() -> TestResult<()> {
	common_tests::common_test_chat_multi_binary_b64_ok(MODEL_FLASH_2_5).await
}

// endregion: --- Binary Tests

// region:    --- Tool Tests

#[tokio::test]
async fn test_tool_simple_ok() -> TestResult<()> {
	common_tests::common_test_tool_simple_ok(MODEL_FLASH_2_5).await
}

#[tokio::test]
async fn test_tool_full_flow_ok() -> TestResult<()> {
	common_tests::common_test_tool_full_flow_ok(MODEL_FLASH_2_5).await
}

#[tokio::test]
async fn test_tool_deterministic_history_gemini_3_ok() -> TestResult<()> {
	use genai::chat::{ChatMessage, ChatRequest, Tool, ToolCall, ToolResponse};
	use serde_json::json;

	let client = genai::Client::default();

	let weather_tool = Tool::new("get_weather").with_schema(json!({
		"type": "object",
		"properties": {
			"city": { "type": "string" },
			"unit": { "type": "string", "enum": ["C", "F"] }
		},
		"required": ["city", "unit"]
	}));

	// Pre-seed history with a "synthetic" tool call (missing thought signatures)
	let messages = vec![
		ChatMessage::user("What's the weather like in Paris?"),
		ChatMessage::assistant(vec![ToolCall {
			call_id: "call_123".to_string(),
			fn_name: "get_weather".to_string(),
			fn_arguments: json!({"city": "Paris", "unit": "C"}),
			thought_signatures: None,
		}]),
		ChatMessage::from(ToolResponse::new(
			"call_123".to_string(),
			json!({"temperature": 15, "condition": "Cloudy"}).to_string(),
		)),
	];

	let chat_req = ChatRequest::new(messages).with_tools(vec![weather_tool]);

	// This verifies that the adapter correctly injects 'skip_thought_signature_validator'.
	// (Otherwise Gemini 3 would return a 400 error.)
	let chat_res = client.exec_chat(MODEL_GPRO_3, chat_req, None).await?;

	assert!(
		chat_res.first_text().is_some(),
		"Expected a text response from the model"
	);

	Ok(())
}

// NOTE: Issue of this test is that it is pretty slow
#[tokio::test]
async fn test_tool_google_web_search_ok() -> TestResult<()> {
	use genai::chat::{ChatRequest, Tool};
	use serde_json::json;

	// -- Fixtures & Setup
	let client = genai::Client::default();
	let web_search_tool = Tool::new("googleSearch").with_config(json!({}));
	let chat_req =
		ChatRequest::from_user("What is the latest version of Rust? (be concise)").append_tool(web_search_tool);

	// Exec
	let res = client.exec_chat(MODEL_FLASH_3, chat_req, None).await?;

	// Check
	let res_txt = res.content.into_first_text().ok_or("Should have result")?;
	assert!(res_txt.contains("Rust"), "should contains 'Rust'");

	Ok(())
}

// endregion: --- Tool Tests

// region:    --- Resolver Tests

#[tokio::test]
async fn test_resolver_auth_ok() -> TestResult<()> {
	common_tests::common_test_resolver_auth_ok(MODEL_FLASH_2_5, AuthData::from_env("GEMINI_API_KEY")).await
}

// endregion: --- Resolver Tests

// region:    --- List

#[tokio::test]
async fn test_list_models() -> TestResult<()> {
	common_tests::common_test_list_models(AdapterKind::Gemini, "gemini-3-pro-preview").await
}

// endregion: --- List
