use sigil_stitch::code_block::{CodeBlock, StringLitArg};
use sigil_stitch::lang::kotlin::Kotlin;
use sigil_stitch::spec::field_spec::FieldSpec;
use sigil_stitch::spec::file_spec::FileSpec;
use sigil_stitch::spec::fun_spec::{FunSpec, TypeParamSpec};
use sigil_stitch::spec::modifiers::{TypeKind, Visibility};
use sigil_stitch::spec::parameter_spec::ParameterSpec;
use sigil_stitch::spec::type_spec::TypeSpec;
use sigil_stitch::type_name::TypeName;
fn main() {
let list = TypeName::importable("kotlin.collections", "List");
let mutable_list = TypeName::importable("kotlin.collections", "MutableList");
let array_list = TypeName::importable("kotlin.collections", "ArrayList");
let coroutine_scope = TypeName::importable("kotlinx.coroutines", "CoroutineScope");
let uuid = TypeName::importable("java.util", "UUID");
let priority = TypeSpec::builder("Priority", TypeKind::Enum);
let priority = priority.doc("Task priority levels.");
let mut constants = CodeBlock::builder();
constants.add("LOW,", ());
constants.add_line();
constants.add("MEDIUM,", ());
constants.add_line();
constants.add("HIGH,", ());
constants.add_line();
constants.add("CRITICAL", ());
constants.add_line();
let priority = priority.extra_member(constants.build().unwrap());
let priority_spec = priority.build().unwrap();
let tp = TypeParamSpec::new("T");
let repo_spec = TypeSpec::builder("Repository", TypeKind::Interface)
.add_type_param(tp)
.doc("Generic repository for data persistence.")
.doc("")
.doc("@param T the entity type")
.add_method(
FunSpec::builder("findById")
.returns(TypeName::primitive("T?"))
.add_param(ParameterSpec::new("id", TypeName::primitive("String")).unwrap())
.build()
.unwrap(),
)
.add_method(
FunSpec::builder("findAll")
.returns(list.clone())
.build()
.unwrap(),
)
.add_method(
FunSpec::builder("save")
.add_param(ParameterSpec::new("entity", TypeName::primitive("T")).unwrap())
.build()
.unwrap(),
)
.build()
.unwrap();
let task_spec = TypeSpec::builder("Task", TypeKind::Struct)
.doc("A task entity.")
.add_field(
FieldSpec::builder("id", TypeName::primitive("String"))
.is_readonly()
.build()
.unwrap(),
)
.add_field(
FieldSpec::builder("name", TypeName::primitive("String"))
.is_readonly()
.build()
.unwrap(),
)
.add_field(
FieldSpec::builder("priority", TypeName::primitive("Priority"))
.is_readonly()
.build()
.unwrap(),
)
.add_field(
FieldSpec::builder("completed", TypeName::primitive("Boolean"))
.initializer(CodeBlock::of("false", ()).unwrap())
.build()
.unwrap(),
)
.build()
.unwrap();
let base_svc = TypeSpec::builder("BaseService", TypeKind::Class);
let base_svc = base_svc.is_abstract();
let base_svc = base_svc.doc("Base class for services with logging.");
let base_svc = base_svc.add_field(
FieldSpec::builder("serviceName", TypeName::primitive("String"))
.visibility(Visibility::Protected)
.is_readonly()
.build()
.unwrap(),
);
let log_body = CodeBlock::of("println(\"[$serviceName] $message\")", ()).unwrap();
let base_svc = base_svc.add_method(
FunSpec::builder("log")
.visibility(Visibility::Protected)
.add_param(ParameterSpec::new("message", TypeName::primitive("String")).unwrap())
.body(log_body)
.build()
.unwrap(),
);
let base_svc = base_svc.add_method(
FunSpec::builder("initialize")
.is_abstract()
.build()
.unwrap(),
);
let base_svc_spec = base_svc.build().unwrap();
let task_svc = TypeSpec::builder("TaskService", TypeKind::Class);
let task_svc = task_svc.extends(TypeName::primitive("BaseService"));
let task_svc = task_svc.extends(TypeName::primitive("Repository<Task>"));
let task_svc = task_svc.doc("Task management service.");
let task_svc = task_svc.add_field(
FieldSpec::builder("tasks", mutable_list)
.visibility(Visibility::Private)
.is_readonly()
.initializer(CodeBlock::of("%T()", (array_list,)).unwrap())
.build()
.unwrap(),
);
let init_body = CodeBlock::of(
"log(%S)",
(StringLitArg("TaskService initialized".to_string()),),
)
.unwrap();
let task_svc = task_svc.add_method(
FunSpec::builder("initialize")
.is_override()
.body(init_body)
.build()
.unwrap(),
);
let find_body = CodeBlock::of("return tasks.firstOrNull { it.id == id }", ()).unwrap();
let task_svc = task_svc.add_method(
FunSpec::builder("findById")
.returns(TypeName::primitive("Task?"))
.add_param(ParameterSpec::new("id", TypeName::primitive("String")).unwrap())
.is_override()
.body(find_body)
.build()
.unwrap(),
);
let find_all_body = CodeBlock::of("return %T(tasks)", (list.clone(),)).unwrap();
let task_svc = task_svc.add_method(
FunSpec::builder("findAll")
.returns(list)
.is_override()
.body(find_all_body)
.build()
.unwrap(),
);
let save_body = CodeBlock::of("tasks.add(entity)", ()).unwrap();
let task_svc = task_svc.add_method(
FunSpec::builder("save")
.add_param(ParameterSpec::new("entity", TypeName::primitive("Task")).unwrap())
.is_override()
.body(save_body)
.build()
.unwrap(),
);
let task_svc_spec = task_svc.build().unwrap();
let fetch_body = CodeBlock::of(
"val service = TaskService()\nservice.initialize()\nreturn service.findAll()",
(),
)
.unwrap();
let fetch_tasks = FunSpec::builder("fetchTasks")
.is_async()
.returns(TypeName::primitive("List<Task>"))
.body(fetch_body)
.build()
.unwrap();
let create_body = CodeBlock::of(
"return Task(\n id = %T.randomUUID().toString(),\n name = name,\n priority = priority\n)",
(uuid,),
)
.unwrap();
let create_task = FunSpec::builder("createTask")
.returns(TypeName::primitive("Task"))
.add_param(ParameterSpec::new("name", TypeName::primitive("String")).unwrap())
.add_param(ParameterSpec::new("priority", TypeName::primitive("Priority")).unwrap())
.body(create_body)
.build()
.unwrap();
let scope_trigger = CodeBlock::of("// CoroutineScope: %T", (coroutine_scope,)).unwrap();
let file = FileSpec::builder_with("TaskApp.kt", Kotlin::new())
.add_code(scope_trigger)
.add_type(priority_spec)
.add_type(repo_spec)
.add_type(task_spec)
.add_type(base_svc_spec)
.add_type(task_svc_spec)
.add_function(fetch_tasks)
.add_function(create_task)
.build()
.unwrap();
let output = file.render(80).unwrap();
print!("{output}");
}