//! Generate Swift types using Specta and our rspc-inspired type extraction system
//!
//! This binary automatically discovers all registered operations and queries
//! and generates comprehensive Swift types for the complete Spacedrive API.

use std::path::Path;

// Import our type extraction system
use sd_core::infra::wire::type_extraction::{
	create_spacedrive_api_structure, generate_spacedrive_api,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
	println!("️Generating Swift types using Specta + rspc-inspired type extraction...");

	// Use our automatic type extraction system to discover all operations and queries
	let (operations, queries, types) = generate_spacedrive_api();

	println!(
		"Discovered {} operations and {} queries",
		operations.len(),
		queries.len()
	);

	// Create the API structure
	let api_structure = create_spacedrive_api_structure(&operations, &queries);

	println!("API Structure Summary:");
	println!("  • Core Actions: {}", api_structure.core_actions.len());
	println!(
		"  • Library Actions: {}",
		api_structure.library_actions.len()
	);
	println!("  • Core Queries: {}", api_structure.core_queries.len());
	println!(
		"  • Library Queries: {}",
		api_structure.library_queries.len()
	);

	// Generate Swift code directly from the API structure (like rspc does for TypeScript)
	let generated_content = generate_swift_api_code(&api_structure, &types)?;

	// Export to the Swift client package
	let output_path =
		Path::new("packages/swift-client/Sources/SpacedriveClient/SpacedriveTypes.swift");
	std::fs::write(output_path, &generated_content)?;

	println!("Generated Swift types to: {}", output_path.display());

	// Generate API code using our new functions
	let functions =
		sd_core::infra::wire::type_extraction::extract_api_functions(&operations, &queries);
	let api_code = sd_core::infra::wire::type_extraction::generate_swift_api_code(&functions);

	// Write API code to a separate file
	let api_output_path =
		Path::new("packages/swift-client/Sources/SpacedriveClient/SpacedriveAPI.swift");
	std::fs::write(api_output_path, &api_code)?;

	println!("Generated Swift API code to: {}", api_output_path.display());
	println!("Specta Swift generation completed!");
	println!(
		"All {} operations and {} queries automatically discovered and exported!",
		operations.len(),
		queries.len()
	);

	Ok(())
}

/// Generate Swift code directly from the API structure (similar to rspc's TypeScript generation)
fn generate_swift_api_code(
	api_structure: &sd_core::infra::wire::type_extraction::SpacedriveApiStructure,
	types: &specta::TypeCollection,
) -> Result<String, Box<dyn std::error::Error>> {
	let mut swift_code = String::new();

	// Header
	swift_code.push_str(
		"// Generated by Spacedrive using Specta + rspc-inspired type extraction - DO NOT EDIT\n",
	);

	// Generate all types using Specta Swift (single export call with deduplication)
	let mut swift = specta_swift::Swift::new()
		.header("")
		.naming(specta_swift::NamingConvention::PascalCase)
		.optionals(specta_swift::OptionalStyle::QuestionMark)
		.struct_naming(specta_swift::StructNamingStrategy::AutoRename); // Explicit struct naming

	// Enable initializer generation for structs
	swift.generate_initializers = true;

	// Debug: Print specta-swift version/features to verify we're using the right code
	println!("Using specta-swift with fixes:");
	println!("  • Duplicate name handling: Available");
	println!("  • String enum raw types: Fixed");
	println!("  • Adjacently tagged enums: Fixed");
	println!("  • Enum struct variants: Fixed");

	let individual_types = swift.export(types)?;

	// Debug: Check for known issues in the generated code
	if individual_types.contains("case number(    case") {
		eprintln!("ERROR: Malformed enum syntax detected in generated types!");
		eprintln!("This suggests specta-swift fixes are not active.");
		return Err("Malformed enum generation detected".into());
	}

	if individual_types.contains("private enum TypeKeys:")
		&& individual_types.matches("private enum TypeKeys:").count() > 1
	{
		eprintln!("WARNING: Multiple generic TypeKeys enums detected!");
		eprintln!("This may cause Swift compilation errors.");
	}

	if individual_types.contains(": Codable {")
		&& !individual_types.contains(": String, Codable")
		&& individual_types.contains("case")
		&& individual_types.contains(" = \"")
	{
		eprintln!("WARNING: String enums without String raw type detected!");
	}

	println!(
		"Generated {} characters of Swift code",
		individual_types.len()
	);

	// Post-process to replace JsonValue with JSONValue (Specta generates the helper but field types still reference JsonValue)
	// // Use regex to replace only whole words to avoid corrupting other text
	// use regex::Regex;
	// let re = Regex::new(r"\bJsonValue\b").unwrap();
	// individual_types = re.replace_all(&individual_types, "JSONValue").to_string();

	// // Debug: Print the generated code to see what's happening
	// println!(
	// 	"DEBUG: Generated Swift code length: {}",
	// 	individual_types.len()
	// );
	// if individual_types.contains("case number(") {
	// 	println!("DEBUG: Found malformed enum case");
	// }

	swift_code.push_str(&individual_types);
	swift_code.push('\n');

	// Generate the main API enum
	swift_code.push_str("/// Complete Spacedrive API structure\n");
	swift_code.push_str("public enum SpacedriveApi {\n");
	swift_code.push_str("    case CoreAction(CoreAction)\n");
	swift_code.push_str("    case LibraryAction(LibraryAction)\n");
	swift_code.push_str("    case CoreQuery(CoreQuery)\n");
	swift_code.push_str("    case LibraryQuery(LibraryQuery)\n");
	swift_code.push_str("}\n\n");

	// Add Codable conformance for SpacedriveApi
	swift_code.push_str("extension SpacedriveApi: Codable {\n");
	swift_code.push_str("    public var wireMethod: String {\n");
	swift_code.push_str("        switch self {\n");
	swift_code.push_str("        case .CoreAction: return \"core_action\"\n");
	swift_code.push_str("        case .LibraryAction: return \"library_action\"\n");
	swift_code.push_str("        case .CoreQuery: return \"core_query\"\n");
	swift_code.push_str("        case .LibraryQuery: return \"library_query\"\n");
	swift_code.push_str("        }\n");
	swift_code.push_str("    }\n");
	swift_code.push_str("}\n\n");

	// Generate CoreAction enum
	swift_code.push_str("/// Core-scoped actions\n");
	swift_code.push_str("public enum CoreAction {\n");
	for action in &api_structure.core_actions {
		let variant_name = to_pascal_case(&action.identifier);
		swift_code.push_str(&format!(
			"    case {}(input: {}, output: {})\n",
			variant_name, action.input_type_name, action.output_type_name
		));
	}
	swift_code.push_str("}\n\n");

	// Add Codable conformance for CoreAction
	swift_code.push_str("extension CoreAction: Codable {\n");
	swift_code.push_str("    public var wireMethod: String {\n");
	swift_code.push_str("        switch self {\n");
	for action in &api_structure.core_actions {
		let variant_name = to_pascal_case(&action.identifier);
		swift_code.push_str(&format!(
			"        case .{}: return \"{}\"\n",
			variant_name, action.wire_method
		));
	}
	swift_code.push_str("        }\n");
	swift_code.push_str("    }\n");
	swift_code.push_str("}\n\n");

	// Generate LibraryAction enum
	swift_code.push_str("/// Library-scoped actions\n");
	swift_code.push_str("public enum LibraryAction {\n");
	for action in &api_structure.library_actions {
		let variant_name = to_pascal_case(&action.identifier);
		swift_code.push_str(&format!(
			"    case {}(input: {}, output: {})\n",
			variant_name, action.input_type_name, action.output_type_name
		));
	}
	swift_code.push_str("}\n\n");

	// Add Codable conformance for LibraryAction
	swift_code.push_str("extension LibraryAction: Codable {\n");
	swift_code.push_str("    public var wireMethod: String {\n");
	swift_code.push_str("        switch self {\n");
	for action in &api_structure.library_actions {
		let variant_name = to_pascal_case(&action.identifier);
		swift_code.push_str(&format!(
			"        case .{}: return \"{}\"\n",
			variant_name, action.wire_method
		));
	}
	swift_code.push_str("        }\n");
	swift_code.push_str("    }\n");
	swift_code.push_str("}\n\n");

	// Generate CoreQuery enum
	swift_code.push_str("/// Core-scoped queries\n");
	swift_code.push_str("public enum CoreQuery {\n");
	for query in &api_structure.core_queries {
		let variant_name = to_pascal_case(&query.identifier);
		swift_code.push_str(&format!(
			"    case {}(input: {}, output: {})\n",
			variant_name, query.input_type_name, query.output_type_name
		));
	}
	swift_code.push_str("}\n\n");

	// Add Codable conformance for CoreQuery
	swift_code.push_str("extension CoreQuery: Codable {\n");
	swift_code.push_str("    public var wireMethod: String {\n");
	swift_code.push_str("        switch self {\n");
	for query in &api_structure.core_queries {
		let variant_name = to_pascal_case(&query.identifier);
		swift_code.push_str(&format!(
			"        case .{}: return \"{}\"\n",
			variant_name, query.wire_method
		));
	}
	swift_code.push_str("        }\n");
	swift_code.push_str("    }\n");
	swift_code.push_str("}\n\n");

	// Generate LibraryQuery enum
	swift_code.push_str("/// Library-scoped queries\n");
	swift_code.push_str("public enum LibraryQuery {\n");
	for query in &api_structure.library_queries {
		let variant_name = to_pascal_case(&query.identifier);
		swift_code.push_str(&format!(
			"    case {}(input: {}, output: {})\n",
			variant_name, query.input_type_name, query.output_type_name
		));
	}
	swift_code.push_str("}\n\n");

	// Add Codable conformance for LibraryQuery
	swift_code.push_str("extension LibraryQuery: Codable {\n");
	swift_code.push_str("    public var wireMethod: String {\n");
	swift_code.push_str("        switch self {\n");
	for query in &api_structure.library_queries {
		let variant_name = to_pascal_case(&query.identifier);
		swift_code.push_str(&format!(
			"        case .{}: return \"{}\"\n",
			variant_name, query.wire_method
		));
	}
	swift_code.push_str("        }\n");
	swift_code.push_str("    }\n");
	swift_code.push_str("}\n");

	Ok(swift_code)
}

/// Convert snake_case to PascalCase
fn to_pascal_case(s: &str) -> String {
	s.split('.')
		.map(|part| {
			// Split each part on underscores and convert to PascalCase
			part.split('_')
				.map(|subpart| {
					let mut chars = subpart.chars();
					match chars.next() {
						None => String::new(),
						Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
					}
				})
				.collect::<String>()
		})
		.collect::<Vec<_>>()
		.join("")
}
