use std::{env, fs, path::Path};

use ts_rs::TS;

fn generate_types_content() -> String {
    // 4. Friendly banner
    const HEADER: &str = "// This file was generated by `crates/core/src/bin/generate_types.rs`.\n
// Do not edit this file manually.\n
// If you are an AI, and you absolutely have to edit this file, please confirm with the user first.";

    let decls: Vec<String> = vec![
        services::services::filesystem::DirectoryEntry::decl(),
        services::services::filesystem::DirectoryListResponse::decl(),
        db::models::project::Project::decl(),
        db::models::project::ProjectWithBranch::decl(),
        db::models::project::CreateProject::decl(),
        db::models::project::UpdateProject::decl(),
        db::models::project::SearchResult::decl(),
        db::models::project::SearchMatchType::decl(),
        db::models::task_template::TaskTemplate::decl(),
        db::models::task_template::CreateTaskTemplate::decl(),
        db::models::task_template::UpdateTaskTemplate::decl(),
        db::models::task::TaskStatus::decl(),
        db::models::task::Task::decl(),
        db::models::task::TaskWithAttemptStatus::decl(),
        db::models::task::CreateTask::decl(),
        db::models::task::UpdateTask::decl(),
        utils::response::ApiResponse::<()>::decl(),
        server::routes::config::UserSystemInfo::decl(),
        server::routes::config::Environment::decl(),
        server::routes::task_attempts::CreateFollowUpAttempt::decl(),
        server::routes::task_attempts::CreateGitHubPrRequest::decl(),
        services::services::github_service::GitHubServiceError::decl(),
        services::services::config::Config::decl(),
        services::services::config::NotificationConfig::decl(),
        services::services::config::ThemeMode::decl(),
        services::services::config::EditorConfig::decl(),
        services::services::config::EditorType::decl(),
        services::services::config::GitHubConfig::decl(),
        services::services::config::SoundFile::decl(),
        services::services::auth::DeviceFlowStartResponse::decl(),
        server::routes::auth::DevicePollStatus::decl(),
        server::routes::auth::CheckTokenResponse::decl(),
        services::services::git::GitBranch::decl(),
        services::services::git::BranchStatus::decl(),
        utils::diff::Diff::decl(),
        utils::diff::FileDiffDetails::decl(),
        services::services::github_service::RepositoryInfo::decl(),
        executors::executors::BaseCodingAgent::decl(),
        executors::command::CommandBuilder::decl(),
        executors::command::AgentProfile::decl(),
        executors::command::AgentProfiles::decl(),
        executors::actions::coding_agent_initial::CodingAgentInitialRequest::decl(),
        executors::actions::coding_agent_follow_up::CodingAgentFollowUpRequest::decl(),
        server::routes::task_attempts::CreateTaskAttemptBody::decl(),
        server::routes::task_attempts::RebaseTaskAttemptRequest::decl(),
        db::models::task_attempt::TaskAttempt::decl(),
        db::models::execution_process::ExecutionProcess::decl(),
        db::models::execution_process::ExecutionProcessSummary::decl(),
        db::models::execution_process::ExecutionProcessStatus::decl(),
        db::models::execution_process::ExecutionProcessRunReason::decl(),
        services::services::events::EventPatch::decl(),
        services::services::events::EventPatchInner::decl(),
        services::services::events::RecordTypes::decl(),
        executors::logs::NormalizedConversation::decl(),
        executors::logs::NormalizedEntry::decl(),
        executors::logs::NormalizedEntryType::decl(),
        executors::logs::EditDiff::decl(),
        executors::logs::ActionType::decl(),
        executors::logs::utils::patch::PatchType::decl(),
    ];

    let body = decls
        .into_iter()
        .map(|d| {
            let trimmed = d.trim_start();
            if trimmed.starts_with("export") {
                d
            } else {
                format!("export {trimmed}")
            }
        })
        .collect::<Vec<_>>()
        .join("\n\n");

    format!("{HEADER}\n\n{body}")
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let check_mode = args.iter().any(|arg| arg == "--check");

    // 1. Make sure ../shared exists
    let shared_path = Path::new("shared");
    fs::create_dir_all(shared_path).expect("cannot create shared");

    println!("Generating TypeScript types…");

    // 2. Let ts-rs write its per-type files here (handy for debugging)
    env::set_var("TS_RS_EXPORT_DIR", shared_path.to_str().unwrap());

    let generated = generate_types_content();
    let types_path = shared_path.join("types.ts");

    if check_mode {
        // Read the current file
        let current = fs::read_to_string(&types_path).unwrap_or_default();
        if current == generated {
            println!("✅ shared/types.ts is up to date.");
            std::process::exit(0);
        } else {
            eprintln!("❌ shared/types.ts is not up to date. Please run 'npm run generate-types' and commit the changes.");
            std::process::exit(1);
        }
    } else {
        // Write the file as before
        fs::write(&types_path, generated).expect("unable to write types.ts");
        println!("✅ TypeScript types generated in shared/");
    }
}
