//! Command-line argument definitions.

use clap::{Args as ClapArgs, Parser, Subcommand, ValueEnum};

use crate::parser::{Endian, Radix};

/// Check that a CSV column forms a consecutive sequence.
///
/// With no subcommand, checks the given CSV file: prints nothing by default and
/// reports the result via the exit code (0 = valid, 1 = issues detected,
/// 2 = input/usage error).
#[derive(Debug, Parser)]
#[command(name = "hanuke", version, args_conflicts_with_subcommands = true)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Option<Command>,

    #[command(flatten)]
    pub check: CheckArgs,
}

/// Subcommands. Absent for the default check behavior.
#[derive(Debug, Subcommand)]
pub enum Command {
    /// Print version information
    Version(VersionArgs),
}

#[derive(Debug, ClapArgs)]
pub struct VersionArgs {
    /// Also print the git commit hash the binary was built from
    #[arg(long)]
    pub commit: bool,
}

/// Arguments for the default check behavior.
#[derive(Debug, ClapArgs)]
pub struct CheckArgs {
    /// Input CSV file ("-" reads from stdin). Required unless a subcommand is used.
    pub file: Option<String>,

    /// First column to check (1-based)
    #[arg(short, long, default_value_t = 1)]
    pub col: usize,

    /// Number of columns per record (2 or more combines them as a byte sequence)
    #[arg(short = 'n', long, default_value_t = 1)]
    pub cols: usize,

    /// Interpret values as hexadecimal (optional "0x" prefix accepted)
    #[arg(short = 'x', long)]
    pub hex: bool,

    /// Byte order used when combining multiple columns
    #[arg(long, value_enum, default_value_t = EndianArg::Be)]
    pub endian: EndianArg,

    /// Bytes per column in multi-column mode (default: inferred from the
    /// first data row for hex, 1 for dec)
    #[arg(long, value_parser = clap::value_parser!(u32).range(1..=16))]
    pub col_bytes: Option<u32>,

    /// Skip the first row as a header
    #[arg(long)]
    pub header: bool,

    /// Quote character (single ASCII char; e.g. --quote "'" for single quotes)
    #[arg(long, default_value_t = '"')]
    pub quote: char,

    /// Expected step (negative for descending; must not be 0)
    #[arg(short, long, default_value_t = 1, allow_hyphen_values = true)]
    pub step: i128,

    /// Print check details (start/end values, missing, duplicates, ...) to stdout
    #[arg(short, long, conflicts_with = "show")]
    pub verbose: bool,

    /// Print only the selected information (comma-separated for multiple)
    #[arg(long, value_enum, value_delimiter = ',')]
    pub show: Vec<ShowKind>,

    /// Print the result as a JSON count summary (add --verbose for full issue lists)
    #[arg(long, conflicts_with = "show")]
    pub json: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum EndianArg {
    Le,
    Be,
}

impl From<EndianArg> for Endian {
    fn from(e: EndianArg) -> Self {
        match e {
            EndianArg::Le => Endian::Le,
            EndianArg::Be => Endian::Be,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
pub enum ShowKind {
    /// Start value
    Start,
    /// End value
    End,
    /// Missing values (ranges are printed as first..last)
    Missing,
    /// Duplicate values
    Duplicates,
}

impl CheckArgs {
    pub fn radix(&self) -> Radix {
        if self.hex { Radix::Hex } else { Radix::Dec }
    }
}
