// SPDX-FileCopyrightText: 2024 Aurélien Gâteau <mail@agateau.com>
//
// SPDX-License-Identifier: Apache-2.0

use std::fs;
use std::io;
use std::path::PathBuf;

use clap::{Parser, Subcommand};

use regexnight::lint::lint;
use regexnight::parse::{parse_regex, RegexTree};
use regexnight::print_tree;

#[derive(Parser)]
#[command(version, about)]
pub struct Cli {
    #[clap(subcommand)]
    command: Command,
}

#[derive(Subcommand)]
enum Command {
    /// Print a syntax-highlighted version of the regular expression
    Print {
        /// Read the regular expression from FILE
        #[arg(short, long)]
        file: Option<PathBuf>,
        /// Print the regular expression as a tree
        #[arg(short, long)]
        tree: bool,
        /// Regular expression to process
        regex: Option<String>,
    },
    /// Suggest improvements for the regular expression
    Lint {
        /// Read the regular expression from FILE
        #[arg(short, long)]
        file: Option<PathBuf>,
        /// Regular expression to process
        regex: Option<String>,
    },
    /// Print the internal representation of the regular expression
    Dump {
        /// Read the regular expression from FILE
        #[arg(short, long)]
        file: Option<PathBuf>,
        /// Regular expression to process
        regex: Option<String>,
    },
}

fn read_stdin_line() -> anyhow::Result<String> {
    let mut buffer = String::new();
    let stdin = io::stdin();
    if let Err(err) = stdin.read_line(&mut buffer) {
        return Err(anyhow::anyhow!("Failed to read from stdin: {}", err));
    }
    Ok(buffer.trim_end().into())
}

fn read_regex(path: &Option<PathBuf>, regex_str: &Option<String>) -> anyhow::Result<RegexTree> {
    let regex = match path {
        Some(path) => fs::read_to_string(path)?,
        None => match regex_str {
            Some(x) => x.into(),
            None => read_stdin_line()?,
        },
    };
    parse_regex(regex.trim_end())
}

fn main() -> anyhow::Result<()> {
    let cli = Cli::parse();

    match &cli.command {
        Command::Print {
            file,
            tree: as_tree,
            regex,
        } => {
            let tree = read_regex(file, regex)?;
            if *as_tree {
                print_tree::print_tree(&tree);
            } else {
                print_tree::print(&tree);
            }
        }
        Command::Lint { file, regex } => {
            let tree = read_regex(file, regex)?;
            lint(&tree)?;
        }
        Command::Dump { file, regex } => {
            let tree = read_regex(file, regex)?;
            println!("{}", &tree);
        }
    }
    Ok(())
}
