use json::{object, JsonValue};
#[derive(Clone, Debug)]
pub enum Fields {
    String,
    StringPass,
    StringKey,
    StringTel,
    StringIdent,
    StringEmail,
    StringColor,
    StringCode,
    StringBarcode,
    StringQrcode,
    Radio,
    Select,
    TableList,
    TableTree,
    Int,
    Switch,
    Dict,
    Text,
    TextEditor,
    TextUrl,
    Json,
    Array,
    Object,
    Float,
    DateTime,
    Year,
}
impl Fields {
    pub fn name(&mut self, name: &str) -> Field {
        Field::new(self.clone(), name)
    }
    pub fn str(self) -> &'static str {
        match self {
            Fields::String
            | Fields::StringPass
            | Fields::StringKey
            | Fields::StringTel
            | Fields::StringIdent
            | Fields::StringEmail
            | Fields::StringColor
            | Fields::StringCode
            | Fields::StringBarcode
            | Fields::StringQrcode => "string",
            Fields::Radio => "radio",
            Fields::Select => "select",
            Fields::TableList => "table",
            Fields::TableTree => "tree",
            Fields::Int => "int",
            Fields::Switch => "bool",
            Fields::Dict => "string",
            Fields::Text | Fields::TextEditor | Fields::TextUrl => "text",
            Fields::Json => "json",
            Fields::Array => "array",
            Fields::Object => "object",
            Fields::Float => "float",
            Fields::DateTime => "datetime",
            Fields::Year => "year",
        }
    }
}
#[derive(Debug)]
pub struct Field {
    mode: Fields,
    /// 必填
    require: bool,
    field: String,
    title: String,
    /// 默认值
    def: JsonValue,
    /// 长度
    length: usize,
    /// 小数点位数
    dec: usize,
    /// 选择项目
    option: Vec<&'static str>,
    /// 是否显示
    show: bool,
    describe: String,
    /// 示例
    example: JsonValue,
    /// 接口
    api: String,
    /// 表名称
    table_name: String,
    /// 是否多选
    multiple: bool,
}

impl Field {
    pub fn new(mode: Fields, name: &str) -> Field {
        Self {
            mode,
            require: true,
            field: name.to_string(),
            title: "".to_string(),
            def: JsonValue::Null,
            length: 0,
            dec: 0,
            option: vec![],
            show: true,
            describe: "".to_string(),
            example: JsonValue::Null,
            api: "".to_string(),
            table_name: "".to_string(),
            multiple: false,
        }
    }
    pub fn title(mut self, name: &str) -> Field {
        self.title = name.to_string();
        self
    }
    /// 默认值
    pub fn def(mut self, name: JsonValue) -> Field {
        self.def = name;
        self
    }
    pub fn require(mut self, require: bool) -> Field {
        self.require = require;
        self
    }
    pub fn show(mut self, show: bool) -> Field {
        self.show = show;
        self
    }
    pub fn example(mut self, example: JsonValue) -> Field {
        self.example = example;
        self
    }
    pub fn length(mut self, length: usize) -> Field {
        self.length = length;
        self
    }
    pub fn describe(mut self, describe: &str) -> Field {
        self.describe = describe.to_string();
        self
    }
    pub fn option(mut self, option: Vec<&'static str>) -> Field {
        self.option = option;
        self
    }
    /// 关联数据表配置
    pub fn table(mut self, table: &str, api: &str, fields: Vec<&'static str>) -> Field {
        self.api = api.to_string();
        self.table_name = table.to_string();
        self.option = fields;
        self
    }
    pub fn multiple(mut self, multiple: bool, count: usize) -> Field {
        self.multiple = multiple;
        if count == 0 {
            self.length = 1
        } else {
            self.length = count;
        }
        self
    }
    pub fn dec(mut self, dec: usize) -> Field {
        self.dec = dec;
        self
    }
    pub fn sql(self) -> JsonValue {
        object! {}
    }
    pub fn swagger(self) -> JsonValue {
        object! {
            "type": self.mode.str(),
            "example": self.example,
        }
    }
    pub fn field(self) -> JsonValue {
        let example = if self.example.is_empty() {
            self.def.clone()
        } else {
            self.example
        };
        let mut field = object! {
            "require"=> self.require,
            "field"=> self.field,
            "title"=> self.title,
            "show"=> self.show,
            "describe"=> self.describe,
            "example"=> example
        };
        match self.mode {
            Fields::String
            | Fields::StringPass
            | Fields::StringKey
            | Fields::StringTel
            | Fields::StringIdent
            | Fields::StringEmail
            | Fields::StringColor
            | Fields::StringCode
            | Fields::StringBarcode
            | Fields::StringQrcode => {
                field["length"] = self.length.into();
                field["def"] = self.def;
            }
            Fields::Radio => {
                field["option"] = self.option.into();
                field["def"] = self.def;
            }
            Fields::Select => {
                field["option"] = self.option.into();
                field["def"] = self.def;
            }
            Fields::TableList | Fields::TableTree | Fields::Dict => {
                field["option"] = self.option.into();
                field["def"] = self.def;
                field["api"] = self.api.into();
                field["table"] = self.table_name.into();
                field["multiple"] = self.multiple.into();
                field["length"] = self.length.into();
            }
            Fields::Int => {
                field["length"] = self.length.into();
                field["def"] = self.def;
            }
            Fields::Switch => {
                field["def"] = self.def;
            }
            Fields::Text
            | Fields::TextEditor
            | Fields::TextUrl
            | Fields::Json
            | Fields::Array
            | Fields::Object => {
                field["length"] = self.length.into();
                field["def"] = self.def;
            }
            Fields::Float => {
                field["length"] = self.length.into();
                field["dec"] = self.dec.into();
                field["def"] = self.def;
            }
            Fields::DateTime => {
                field["def"] = self.def;
            }
            Fields::Year => {
                field["def"] = self.def;
            }
        };
        field
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use json::JsonValue;

    #[test]
    fn fields_str_string_variants() {
        assert_eq!(Fields::String.str(), "string");
        assert_eq!(Fields::StringPass.str(), "string");
        assert_eq!(Fields::StringKey.str(), "string");
        assert_eq!(Fields::StringTel.str(), "string");
        assert_eq!(Fields::StringIdent.str(), "string");
        assert_eq!(Fields::StringEmail.str(), "string");
        assert_eq!(Fields::StringColor.str(), "string");
        assert_eq!(Fields::StringCode.str(), "string");
        assert_eq!(Fields::StringBarcode.str(), "string");
        assert_eq!(Fields::StringQrcode.str(), "string");
    }

    #[test]
    fn fields_str_other_variants() {
        assert_eq!(Fields::Radio.str(), "radio");
        assert_eq!(Fields::Select.str(), "select");
        assert_eq!(Fields::TableList.str(), "table");
        assert_eq!(Fields::TableTree.str(), "tree");
        assert_eq!(Fields::Int.str(), "int");
        assert_eq!(Fields::Switch.str(), "bool");
        assert_eq!(Fields::Dict.str(), "string");
        assert_eq!(Fields::Text.str(), "text");
        assert_eq!(Fields::TextEditor.str(), "text");
        assert_eq!(Fields::TextUrl.str(), "text");
        assert_eq!(Fields::Json.str(), "json");
        assert_eq!(Fields::Array.str(), "array");
        assert_eq!(Fields::Object.str(), "object");
        assert_eq!(Fields::Float.str(), "float");
        assert_eq!(Fields::DateTime.str(), "datetime");
        assert_eq!(Fields::Year.str(), "year");
    }

    #[test]
    fn fields_name_creates_field() {
        let f = Fields::Int.name("age");
        assert_eq!(f.field, "age");
        assert!(matches!(f.mode, Fields::Int));
    }

    #[test]
    fn field_new_defaults() {
        let f = Field::new(Fields::String, "name");
        assert!(matches!(f.mode, Fields::String));
        assert!(f.require);
        assert!(f.show);
        assert_eq!(f.field, "name");
        assert_eq!(f.title, "");
        assert!(f.def.is_null());
        assert_eq!(f.length, 0);
        assert_eq!(f.dec, 0);
        assert!(f.option.is_empty());
        assert_eq!(f.describe, "");
        assert!(f.example.is_null());
        assert_eq!(f.api, "");
        assert_eq!(f.table_name, "");
        assert!(!f.multiple);
    }

    #[test]
    fn field_title() {
        let res = Fields::String.name("x").title("My Title").field();
        assert_eq!(res["title"], "My Title");
    }

    #[test]
    fn field_def() {
        let res = Fields::String.name("x").def("default_val".into()).field();
        assert_eq!(res["def"], "default_val");
    }

    #[test]
    fn field_require_false() {
        let res = Fields::String.name("x").require(false).field();
        assert_eq!(res["require"], false);
    }

    #[test]
    fn field_show_false() {
        let res = Fields::String.name("x").show(false).field();
        assert_eq!(res["show"], false);
    }

    #[test]
    fn field_example_set() {
        let res = Fields::String.name("x").example("ex".into()).field();
        assert_eq!(res["example"], "ex");
    }

    #[test]
    fn field_length() {
        let res = Fields::String.name("x").length(50).field();
        assert_eq!(res["length"], 50);
    }

    #[test]
    fn field_describe() {
        let res = Fields::String.name("x").describe("desc text").field();
        assert_eq!(res["describe"], "desc text");
    }

    #[test]
    fn field_option() {
        let res = Fields::Radio.name("x").option(vec!["a", "b"]).field();
        assert_eq!(res["option"][0], "a");
        assert_eq!(res["option"][1], "b");
    }

    #[test]
    fn field_table() {
        let res = Fields::TableList
            .name("x")
            .table("my_table", "/api/list", vec!["col1", "col2"])
            .field();
        assert_eq!(res["table"], "my_table");
        assert_eq!(res["api"], "/api/list");
        assert_eq!(res["option"][0], "col1");
        assert_eq!(res["option"][1], "col2");
    }

    #[test]
    fn field_multiple_count_zero() {
        let f = Field::new(Fields::TableList, "x").multiple(true, 0);
        assert!(f.multiple);
        assert_eq!(f.length, 1);
    }

    #[test]
    fn field_multiple_count_nonzero() {
        let f = Field::new(Fields::TableList, "x").multiple(true, 5);
        assert!(f.multiple);
        assert_eq!(f.length, 5);
    }

    #[test]
    fn field_dec() {
        let res = Fields::Float.name("x").dec(4).field();
        assert_eq!(res["dec"], 4);
    }

    #[test]
    fn field_sql_returns_empty_object() {
        let res = Fields::String.name("x").sql();
        assert!(res.is_object());
        assert_eq!(res.len(), 0);
    }

    #[test]
    fn field_swagger_returns_type_and_example() {
        let res = Fields::Int.name("x").example(42.into()).swagger();
        assert_eq!(res["type"], "int");
        assert_eq!(res["example"], 42);
    }

    #[test]
    fn field_output_string_variants() {
        let variants = [
            Fields::String,
            Fields::StringPass,
            Fields::StringKey,
            Fields::StringTel,
            Fields::StringIdent,
            Fields::StringEmail,
            Fields::StringColor,
            Fields::StringCode,
            Fields::StringBarcode,
            Fields::StringQrcode,
        ];
        for mut v in variants {
            let res = v.name("s").length(100).def("d".into()).field();
            assert_eq!(res["length"], 100);
            assert_eq!(res["def"], "d");
        }
    }

    #[test]
    fn field_output_radio() {
        let res = Fields::Radio
            .name("r")
            .option(vec!["yes", "no"])
            .def("yes".into())
            .field();
        assert_eq!(res["option"][0], "yes");
        assert_eq!(res["option"][1], "no");
        assert_eq!(res["def"], "yes");
        assert!(res["length"].is_null());
    }

    #[test]
    fn field_output_select() {
        let res = Fields::Select
            .name("s")
            .option(vec!["a", "b", "c"])
            .def("a".into())
            .field();
        assert_eq!(res["option"].len(), 3);
        assert_eq!(res["def"], "a");
        assert!(res["length"].is_null());
    }

    #[test]
    fn field_output_table_list() {
        let res = Fields::TableList
            .name("t")
            .table("tbl", "/api", vec!["f1"])
            .multiple(true, 3)
            .def("x".into())
            .field();
        assert_eq!(res["option"][0], "f1");
        assert_eq!(res["def"], "x");
        assert_eq!(res["api"], "/api");
        assert_eq!(res["table"], "tbl");
        assert_eq!(res["multiple"], true);
        assert_eq!(res["length"], 3);
    }

    #[test]
    fn field_output_table_tree() {
        let res = Fields::TableTree
            .name("t")
            .table("tree_tbl", "/tree", vec!["c1", "c2"])
            .multiple(false, 0)
            .def(JsonValue::Null)
            .field();
        assert_eq!(res["table"], "tree_tbl");
        assert_eq!(res["api"], "/tree");
        assert_eq!(res["multiple"], false);
        assert_eq!(res["length"], 1);
    }

    #[test]
    fn field_output_dict() {
        let res = Fields::Dict
            .name("d")
            .table("dict_tbl", "/dict", vec!["k"])
            .def("v".into())
            .field();
        assert_eq!(res["table"], "dict_tbl");
        assert_eq!(res["api"], "/dict");
        assert_eq!(res["def"], "v");
        assert!(!res["multiple"].is_null());
    }

    #[test]
    fn field_output_int() {
        let res = Fields::Int.name("i").length(11).def(0.into()).field();
        assert_eq!(res["length"], 11);
        assert_eq!(res["def"], 0);
    }

    #[test]
    fn field_output_switch() {
        let res = Fields::Switch.name("sw").def(true.into()).field();
        assert_eq!(res["def"], true);
        assert!(res["length"].is_null());
    }

    #[test]
    fn field_output_text_variants() {
        let variants = [
            Fields::Text,
            Fields::TextEditor,
            Fields::TextUrl,
            Fields::Json,
            Fields::Array,
            Fields::Object,
        ];
        for mut v in variants {
            let res = v.name("t").length(5000).def("body".into()).field();
            assert_eq!(res["length"], 5000);
            assert_eq!(res["def"], "body");
        }
    }

    #[test]
    fn field_output_float() {
        let res = Fields::Float
            .name("f")
            .length(10)
            .dec(2)
            .def(1.5.into())
            .field();
        assert_eq!(res["length"], 10);
        assert_eq!(res["dec"], 2);
        assert_eq!(res["def"], 1.5);
    }

    #[test]
    fn field_output_datetime() {
        let res = Fields::DateTime.name("dt").def("2026-01-01".into()).field();
        assert_eq!(res["def"], "2026-01-01");
        assert!(res["length"].is_null());
    }

    #[test]
    fn field_output_year() {
        let res = Fields::Year.name("y").def(2026.into()).field();
        assert_eq!(res["def"], 2026);
        assert!(res["length"].is_null());
    }

    #[test]
    fn field_example_fallback_to_def() {
        let res = Fields::String.name("x").def("fallback".into()).field();
        assert_eq!(res["example"], "fallback");
    }

    #[test]
    fn field_example_explicit_overrides_def() {
        let res = Fields::String
            .name("x")
            .def("default".into())
            .example("explicit".into())
            .field();
        assert_eq!(res["example"], "explicit");
    }
}
