mod cache;
mod commands;
mod conf;
mod data;
mod indexer;
mod keys;
mod runtime_config;
mod utils;

use anyhow::anyhow;
use clap::Parser;
use codec::Encode;
use data::*;
use keys::*;
use runtime_config::*;
use serde::Deserialize;
use sp_core::{sr25519::Pair, Pair as _};
use subxt::{
	blocks::ExtrinsicEvents,
	events::StaticEvent,
	tx::{BaseExtrinsicParamsBuilder, PairSigner, StaticTxPayload, TxPayload, TxStatus},
};
use utils::*;

/// define command line arguments
#[derive(Clone, clap::Parser, Debug, Default)]
#[clap(author, version, about, long_about = None)]
pub struct Args {
	/// Subcommands
	#[clap(subcommand)]
	pub subcommand: Subcommand,
	/// Overwrite indexer endpoint
	#[clap(short, long)]
	indexer: Option<String>,
	/// Do not use indexer
	#[clap(long)]
	no_indexer: bool,
	/// Secret key or BIP39 mnemonic
	/// (eventually followed by derivation path)
	#[clap(short, long)]
	secret: Option<String>,
	/// Secret key format (seed, substrate)
	#[clap(short = 'S', long, default_value = SecretFormat::Substrate)]
	secret_format: SecretFormat,
	/// Address
	#[clap(short, long)]
	address: Option<String>,
	/// Overwrite duniter websocket RPC endpoint
	#[clap(short, long)]
	url: Option<String>,
	/// Target network (local, gdev, gtest...)
	#[clap(short, long)]
	network: Option<String>,
	/// prevent waiting for extrinsic completion
	#[clap(long)]
	no_wait: bool,
}

/// define subcommands
#[derive(Clone, Debug, clap::Subcommand, Default)]
pub enum Subcommand {
	/// Nothing
	#[default]
	#[clap(hide = true)]
	DoNothing,
	/// Account (balance, transfer...)
	#[clap(subcommand)]
	Account(commands::account::Subcommand),
	/// Identity (get, create, confirm, revoke...)
	#[clap(subcommand)]
	Identity(commands::identity::Subcommand),
	/// Smith (certify, go-online, go-offline...)
	#[clap(subcommand)]
	Smith(commands::smith::Subcommand),
	/// Tech (list members, proposals, vote...)
	#[clap(subcommand)]
	Tech(commands::collective::Subcommand),
	/// Universal Dividend (claim...)
	#[clap(subcommand)]
	Ud(commands::ud::Subcommand),
	/// Oneshot account (balance, create, consume...)
	#[clap(subcommand)]
	Oneshot(commands::oneshot::Subcommand),
	/// Blockchain (current block, runtime info...)
	#[clap(subcommand)]
	Blockchain(commands::blockchain::Subcommand),
	/// Indexer (check, latest block)
	#[clap(subcommand)]
	Indexer(indexer::Subcommand),
	/// Config (show, save...)
	#[clap(subcommand)]
	Config(conf::Subcommand),
}

/// main function
#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), GcliError> {
	// init logger
	env_logger::init();

	// parse argument and initialize data
	let data = Data::new(Args::parse());

	// match subcommands
	match data.args.subcommand.clone() {
		Subcommand::DoNothing => Ok(()),
		Subcommand::Account(subcommand) => {
			commands::account::handle_command(data, subcommand).await
		}
		Subcommand::Identity(subcommand) => {
			commands::identity::handle_command(data, subcommand).await
		}
		Subcommand::Smith(subcommand) => commands::smith::handle_command(data, subcommand).await,
		Subcommand::Tech(subcommand) => {
			commands::collective::handle_command(data, subcommand).await
		}
		Subcommand::Ud(subcommand) => commands::ud::handle_command(data, subcommand).await,
		Subcommand::Oneshot(subcommand) => {
			commands::oneshot::handle_command(data, subcommand).await
		}
		Subcommand::Blockchain(subcommand) => {
			commands::blockchain::handle_command(data, subcommand).await
		}
		Subcommand::Indexer(subcommand) => indexer::handle_command(data, subcommand).await,
		Subcommand::Config(subcommand) => conf::handle_command(data, subcommand),
	}
	.map_err(|e| dbg!(e).into())
}