use super::prelude::*;
use crate::path::{path_get_path, path_get_paths};

#[derive(Default)]
struct Options {
    all: bool,
    quiet: bool,
    find_path: bool,
}

pub fn r#command(
    parser: &mut Parser,
    streams: &mut IoStreams,
    argv: &mut [&wstr],
) -> BuiltinResult {
    let cmd = argv[0];
    let argc = argv.len();
    let print_hints = false;
    let mut opts: Options = Default::default();

    let shortopts: &wstr = L!("hasqv");
    let longopts: &[WOption] = &[
        wopt(L!("help"), ArgType::NoArgument, 'h'),
        wopt(L!("all"), ArgType::NoArgument, 'a'),
        wopt(L!("query"), ArgType::NoArgument, 'q'),
        wopt(L!("quiet"), ArgType::NoArgument, 'q'),
        wopt(L!("search"), ArgType::NoArgument, 's'),
    ];

    let mut w = WGetopter::new(shortopts, longopts, argv);
    while let Some(c) = w.next_opt() {
        match c {
            'a' => opts.all = true,
            'q' => opts.quiet = true,
            's' => opts.find_path = true,
            // -s and -v are aliases
            'v' => opts.find_path = true,
            'h' => {
                builtin_print_help(parser, streams, cmd);
                return Ok(SUCCESS);
            }
            ':' => {
                builtin_missing_argument(
                    parser,
                    streams,
                    cmd,
                    None,
                    argv[w.wopt_index - 1],
                    print_hints,
                );
                return Err(STATUS_INVALID_ARGS);
            }
            ';' => {
                builtin_unexpected_argument(
                    parser,
                    streams,
                    cmd,
                    argv[w.wopt_index - 1],
                    print_hints,
                );
                return Err(STATUS_INVALID_ARGS);
            }
            '?' => {
                builtin_unknown_option(parser, streams, cmd, argv[w.wopt_index - 1], print_hints);
                return Err(STATUS_INVALID_ARGS);
            }
            _ => {
                panic!("unexpected retval from wgeopter.next()");
            }
        }
    }

    // Quiet implies find_path.
    if !opts.find_path && !opts.all && !opts.quiet {
        builtin_print_help(parser, streams, cmd);
        return Err(STATUS_INVALID_ARGS);
    }

    let mut res = false;
    let optind = w.wopt_index;
    for arg in argv.iter().take(argc).skip(optind) {
        let paths = if opts.all {
            path_get_paths(arg, parser.vars())
        } else {
            match path_get_path(arg, parser.vars()) {
                Some(p) => vec![p],
                None => vec![],
            }
        };
        for path in paths.iter() {
            res = true;
            if opts.quiet {
                return Ok(SUCCESS);
            }

            streams.out.appendln(path);
            if !opts.all {
                break;
            }
        }
    }

    if res {
        Ok(SUCCESS)
    } else {
        Err(STATUS_CMD_UNKNOWN)
    }
}
