use schemars::{
    r#gen::SchemaGenerator,
    schema::{InstanceType, ObjectValidation, Schema, SchemaObject, SubschemaValidation},
};

#[cfg(feature = "ruledocs")]
use crate::rules::RuleEnum;

/// These rules are not verified to have a valid schema
/// These should return the DummyRule struct/schema instead of the actual rule struct/schema,
/// until we verify that the rule's schema is valid and can be generated by schemars.
#[cfg(feature = "ruledocs")]
const NO_VERIFIED_VALID_SCHEMA: [&str; 6] = [
    "jest/prefer-lowercase-title",   // has options from other rule #23186
    "jest/valid-title",              // has options from other rule #23186
    "vitest/prefer-lowercase-title", // has options from other rule #23186
    "vitest/valid-title",            // has options from other rule #23186
    "unicorn/filename-case",         // missing options #23248
    "eslint/no-restricted-globals",  // missing options #23617
];

/// Should this rule be skipped for config schema generation?
/// We skip rules that don't have verified valid schemas to avoid generating invalid schemas.
#[cfg(feature = "ruledocs")]
pub fn should_skip_config_schema(rule_name: &RuleEnum) -> bool {
    let name = format!("{}/{}", rule_name.plugin_name(), rule_name.name());
    NO_VERIFIED_VALID_SCHEMA.contains(&name.as_str())
}

/// Generates a JSON schema for an object where the keys are strings and the values are either strings or null.
/// TS type equivalent: `Record<string, string | null>`
pub fn object_with_nullable_string_schema(_gen: &mut SchemaGenerator) -> Schema {
    let value_schema = SchemaObject {
        subschemas: Some(Box::new(SubschemaValidation {
            any_of: Some(vec![
                SchemaObject {
                    instance_type: Some(InstanceType::String.into()),
                    ..Default::default()
                }
                .into(),
                SchemaObject {
                    instance_type: Some(InstanceType::Null.into()),
                    ..Default::default()
                }
                .into(),
            ]),
            ..Default::default()
        })),
        ..Default::default()
    };

    SchemaObject {
        instance_type: Some(InstanceType::Object.into()),
        object: Some(Box::new(ObjectValidation {
            additional_properties: Some(Box::new(value_schema.into())),
            ..Default::default()
        })),
        ..Default::default()
    }
    .into()
}
