use std::net::SocketAddr;

use shared::core;
use cli_renderer::RenderLayoutKind;
use clap::{Parser, Subcommand};

use clap::*;

#[derive(Parser)]
pub struct Cli {
  #[command(subcommand)]
  pub command: CliCommand,
}

#[derive(Subcommand)]
pub enum CliCommand {
  #[command(name = "ping")]
  Ping {
    #[command(subcommand)]
    ping_cmd: CliPingCommand,
  },

  /// Peer related Cmd
  #[command(name = "peer")]
  Peer {
    #[command(subcommand)]
    peer_cmd: CliPeerCommand,
  },

  /// Block related Cmd
  #[command(name = "block")]
  Block {
    #[command(subcommand)]
    block_cmd: CliBlockCommand,
  },

  #[command(name = "award")]
  Award {
    #[arg(short, long)]
    amount: u64,
    #[arg(short, long)]
    address: String,
  },

  /// Make a Transaction
  #[command(name = "tx")]
  Transaction(core::Tx),

  /// Start new TcpListner on Addr
  #[command(name = "listen")]
  StartListner { addr: String },

  /// Display Node id
  #[command(name = "id")]
  DebugShowId,

  /// Connect to Seed Nodes
  #[command(name = "seed")]
  Seeds {
    #[command(subcommand)]
    seed_cmd: CliSeedCommand,
  },

  /// Clear Pane
  #[command(name = "clear", aliases = ["c"])]
  Clear,

  /// Set TUI layout
  #[command(name = "layout", aliases = ["lay"])]
  Layout { mode: RenderLayoutKind },
}

#[derive(Subcommand)]
pub enum CliPeerCommand {
  /// Connect To Peer With IpAddr
  #[command(name = "connect", aliases = ["c", "con"])]
  Connect { addr: String },

  /// Remove Peer Connection
  #[command(name = "remove", aliases = ["rm"])]
  Remove { id: String },

  /// List Connected Peers
  #[command(name = "list", aliases = ["ls", "l"])]
  List,
}

#[derive(Subcommand)]
pub enum CliSeedCommand {
  /// Connect to Seed nodes
  #[command(name = "connect", aliases = ["c", "con"])]
  Connect,
}

#[derive(Subcommand)]
pub enum CliBlockCommand {
  /// List Blocks in Chain
  #[command(name = "list", aliases = ["ls", "l"])]
  List,

  /// Create and Broadcast new Block
  #[command(name = "create", aliases = ["c", "new"])]
  Create,

  /// Display Block by Hash
  #[command(name = "display", aliases = ["d"])]
  #[group(multiple = false)]
  Display {
    /// Block Hash
    #[arg(long)]
    key: Option<String>,
    /// Block Height
    #[arg(long)]
    height: Option<u64>,
  },
}

#[derive(Subcommand)]
pub enum CliPingCommand {
  /// Ping Peer by Id
  #[command(name = "id", aliases = ["i"])]
  Id {
    #[arg(short, long)]
    id: String,
  },

  /// Ping Peer by Address
  #[command(name = "addr", aliases = ["a", "ad"])]
  Addr {
    #[arg(short, long)]
    addr: String,
  },
}

#[derive(Subcommand)]
#[command(name = "node")]
#[command(about = "A blockchain node CLI tool")]
#[command(version = "1.0")]
#[command(
  long_about = "A comprehensive CLI tool for managing blockchain nodes, peers, and transactions"
)]
pub enum CliNodeCommand {}

#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
pub struct CliArgs {
  /// Provide address on which node will listen
  #[arg(short = 'a', long)]
  pub addr: Option<SocketAddr>,

  /// Provide File with current chain
  #[arg(short = 'd', long)]
  pub database: Option<String>,

  /// Enable bootstrap mode (alternative syntax)
  #[arg(short = 'b', long = "bootstrap", action = clap::ArgAction::SetTrue)]
  pub bootstrap: bool,

  /// Enable debug mode (alternative syntax)
  #[arg(long = "debug", action = clap::ArgAction::SetTrue)]
  pub debug: bool,

  /// Enable rendering (alternative syntax)
  #[arg(short = 'r', long = "render", action = clap::ArgAction::Set, default_value = "true")]
  pub render: bool,

  /// Enable debug mode (alternative syntax)
  #[arg(short = 's', long = "seed", action = clap::ArgAction::SetTrue)]
  pub seed: bool,
}

#[derive(Subcommand, Debug)]
pub enum Commands {}

#[derive(Subcommand, Debug)]
pub enum TxCmd {
  /// Add a new transaction to the DB
  #[command(short_flag = 'a')]
  Add(core::Tx),
}

pub fn get_args() -> CliArgs {
  CliArgs::parse()
}
