use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand, SimplePluginCommand};
use nu_protocol::{Category, LabeledError, Signature, SyntaxShape, Type, Value, record};
use fluent_syntax::parser::parse;
use crate::FluentPlugin;

pub struct ValidateFtl;

impl SimplePluginCommand for ValidateFtl {
    type Plugin = FluentPlugin;

    fn name(&self) -> &str {
        "fluent-validate"
    }

    fn signature(&self) -> Signature {
        Signature::build(PluginCommand::name(self))
            .input_output_type(Type::Any, Type::Record(vec![].into()))
            .required("file", SyntaxShape::Filepath, "FTL file to validate")
            .category(Category::Strings)
    }

    fn description(&self) -> &str {
        "Validate a Fluent Translation List (.ftl) file syntax"
    }

    fn examples(&self) -> Vec<nu_protocol::Example<'_>> {
        vec![
            nu_protocol::Example {
                description: "Validate an FTL file",
                example: "fluent-validate locales/en-US/main.ftl",
                result: None,
            },
        ]
    }

    fn run(
        &self,
        _plugin: &Self::Plugin,
        _engine: &EngineInterface,
        call: &EvaluatedCall,
        _input: &Value,
    ) -> Result<Value, LabeledError> {
        let file_path: String = call.req(0)?;

        let content = std::fs::read_to_string(&file_path)
            .map_err(|e| LabeledError::new("Read error").with_label(format!("Failed to read '{}': {}", file_path, e), call.head))?;

        let parse_result = parse(content);
        let result = match parse_result {
            Ok(_resource) => Value::record(
                record! {
                    "valid" => Value::bool(true, call.head),
                    "file" => Value::string(file_path, call.head),
                    "errors" => Value::list(vec![], call.head),
                },
                call.head,
            ),
            Err((_resource, errors)) => {
                let error_list: Vec<Value> = errors.iter()
                    .map(|err| Value::string(format!("{:?}", err), call.head))
                    .collect();

                Value::record(
                    record! {
                        "valid" => Value::bool(false, call.head),
                        "file" => Value::string(file_path, call.head),
                        "errors" => Value::list(error_list, call.head),
                    },
                    call.head,
                )
            }
        };

        Ok(result)
    }
}