use std::env;
use std::path::PathBuf;

use sgclaw::generated_scene::analyzer::SceneKind;
use sgclaw::generated_scene::generator::{generate_scene_package, GenerateSceneRequest, SceneInfoJson};

fn main() {
    if let Err(err) = run() {
        eprintln!("sg_scene_generate: {err}");
        std::process::exit(1);
    }
}

fn run() -> Result<(), String> {
    let args = parse_args(env::args().skip(1))?;
    let scene_info: Option<SceneInfoJson> = args.scene_info_json
        .map(|json| serde_json::from_str(&json))
        .transpose()
        .map_err(|e| format!("Invalid scene-info-json: {}", e))?;
    let skill_root = generate_scene_package(GenerateSceneRequest {
        source_dir: args.source_dir,
        scene_id: args.scene_id,
        scene_name: args.scene_name,
        scene_kind: args.scene_kind,
        target_url: args.target_url,
        output_root: args.output_root,
        lessons_path: args.lessons_path,
        scene_info_json: scene_info,
    })
    .map_err(|err| err.to_string())?;

    println!("generated scene package: {}", skill_root.display());
    Ok(())
}

struct CliArgs {
    source_dir: PathBuf,
    scene_id: String,
    scene_name: String,
    scene_kind: Option<SceneKind>,
    target_url: Option<String>,
    output_root: PathBuf,
    lessons_path: Option<PathBuf>,
    scene_info_json: Option<String>,
}

fn parse_args(args: impl Iterator<Item = String>) -> Result<CliArgs, String> {
    let mut source_dir = None;
    let mut scene_id = None;
    let mut scene_name = None;
    let mut scene_kind = None;
    let mut target_url = None;
    let mut output_root = None;
    let mut lessons_path = None;
    let mut scene_info_json = None;
    let mut pending_flag: Option<String> = None;

    for arg in args {
        if let Some(flag) = pending_flag.take() {
            match flag.as_str() {
                "--source-dir" => source_dir = Some(PathBuf::from(arg)),
                "--scene-id" => scene_id = Some(arg),
                "--scene-name" => scene_name = Some(arg),
                "--scene-kind" => {
                    scene_kind = Some(
                        SceneKind::from_str(&arg)
                            .ok_or_else(|| format!("invalid scene kind: {}", arg))?,
                    );
                }
                "--target-url" => target_url = Some(arg),
                "--output-root" => output_root = Some(PathBuf::from(arg)),
                "--lessons" => lessons_path = Some(PathBuf::from(arg)),
                "--scene-info-json" => scene_info_json = Some(arg),
                _ => return Err(format!("unsupported argument {flag}")),
            }
            continue;
        }

        match arg.as_str() {
            "--source-dir" | "--scene-id" | "--scene-name" | "--scene-kind" | "--target-url"
            | "--output-root" | "--lessons" | "--scene-info-json" => {
                pending_flag = Some(arg);
            }
            "--help" | "-h" => return Err(usage()),
            _ => return Err(format!("unsupported argument {arg}\n{}", usage())),
        }
    }

    if let Some(flag) = pending_flag {
        return Err(format!("missing value for {flag}"));
    }

    Ok(CliArgs {
        source_dir: source_dir.ok_or_else(usage)?,
        scene_id: scene_id.ok_or_else(usage)?,
        scene_name: scene_name.ok_or_else(usage)?,
        scene_kind,
        target_url,
        output_root: output_root.ok_or_else(usage)?,
        lessons_path,
        scene_info_json,
    })
}

fn usage() -> String {
    "usage: sg_scene_generate --source-dir <scenario-dir> --scene-id <scene-id> --scene-name <display-name> [--scene-kind <report_collection|monitoring>] [--target-url <url>] --output-root <skill-staging-root> [--lessons <lessons-toml>] [--scene-info-json '<json>']".to_string()
}
