package cn.novalon.manage.db.dao;

import org.junit.jupiter.api.Test;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

/**
 * QueryUtil详细测试 - 提升分支覆盖率
 * 
 * @author 张翔
 * @date 2026-03-24
 */
class QueryUtilDetailedTest {

    static class TestQuery {
        @QueryField(propName = "name", type = QueryField.Type.EQUAL)
        private String name;

        @QueryField(propName = "age", type = QueryField.Type.GREATER_THAN)
        private Integer age;

        @QueryField(propName = "score", type = QueryField.Type.LESS_THAN)
        private Integer score;

        @QueryField(propName = "status", type = QueryField.Type.INNER_LIKE)
        private String status;

        @QueryField(propName = "email", type = QueryField.Type.LEFT_LIKE)
        private String email;

        @QueryField(propName = "phone", type = QueryField.Type.RIGHT_LIKE)
        private String phone;

        @QueryField(propName = "roles", type = QueryField.Type.IN)
        private List<String> roles;

        @QueryField(propName = "keyword", blurry = "name,description,content")
        private String keyword;

        @QueryField(propName = "deletedAt", type = QueryField.Type.IS_NULL)
        private String deletedAt;

        @QueryField(propName = "updatedAt", type = QueryField.Type.IS_NOT_NULL)
        private String updatedAt;

        @QueryField(propName = "orField", type = QueryField.Type.OR, orPropVal = QueryField.Type.IS_NULL, orPropNames = {
                "field1", "field2" })
        private String orField;

        public TestQuery() {
        }

        public TestQuery(String name, Integer age, Integer score, String status, String email,
                String phone, List<String> roles, String keyword, String deletedAt,
                String updatedAt, String orField) {
            this.name = name;
            this.age = age;
            this.score = score;
            this.status = status;
            this.email = email;
            this.phone = phone;
            this.roles = roles;
            this.keyword = keyword;
            this.deletedAt = deletedAt;
            this.updatedAt = updatedAt;
            this.orField = orField;
        }

        public String getName() {
            return name;
        }

        public Integer getAge() {
            return age;
        }

        public Integer getScore() {
            return score;
        }

        public String getStatus() {
            return status;
        }

        public String getEmail() {
            return email;
        }

        public String getPhone() {
            return phone;
        }

        public List<String> getRoles() {
            return roles;
        }

        public String getKeyword() {
            return keyword;
        }

        public String getDeletedAt() {
            return deletedAt;
        }

        public String getUpdatedAt() {
            return updatedAt;
        }

        public String getOrField() {
            return orField;
        }
    }

    @Test
    void testNullQuery() {
        Query query = QueryUtil.getQuery(null);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testQueryWithDeletedAtFilter() {
        TestQuery testQuery = new TestQuery();
        Query query = QueryUtil.getQuery(testQuery, true);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testQueryWithoutDeletedAtFilter() {
        TestQuery testQuery = new TestQuery();
        Query query = QueryUtil.getQuery(testQuery, false);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testEqualCondition() {
        TestQuery testQuery = new TestQuery("John", null, null, null, null, null, null, null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testGreaterThanCondition() {
        TestQuery testQuery = new TestQuery(null, 18, null, null, null, null, null, null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testLessThanCondition() {
        TestQuery testQuery = new TestQuery(null, null, 100, null, null, null, null, null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testInnerLikeCondition() {
        TestQuery testQuery = new TestQuery(null, null, null, "active", null, null, null, null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testLeftLikeCondition() {
        TestQuery testQuery = new TestQuery(null, null, null, null, "@example.com", null, null, null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testRightLikeCondition() {
        TestQuery testQuery = new TestQuery(null, null, null, null, null, "123", null, null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testInCondition() {
        TestQuery testQuery = new TestQuery(null, null, null, null, null, null,
                Arrays.asList("admin", "user"), null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testInConditionWithEmptyList() {
        TestQuery testQuery = new TestQuery(null, null, null, null, null, null,
                Collections.emptyList(), null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testBlurrySearchSingleField() {
        TestQuery testQuery = new TestQuery(null, null, null, null, null, null, null, "test", null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testBlurrySearchMultipleFields() {
        TestQuery testQuery = new TestQuery(null, null, null, null, null, null, null, "keyword", null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testIsNullCondition() {
        TestQuery testQuery = new TestQuery(null, null, null, null, null, null, null, null, "null", null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testIsNotNullCondition() {
        TestQuery testQuery = new TestQuery(null, null, null, null, null, null, null, null, null, "value", null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testOrConditionIsNull() {
        TestQuery testQuery = new TestQuery(null, null, null, null, null, null, null, null, null, null, "value");
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testEmptyStringValue() {
        TestQuery testQuery = new TestQuery("", null, null, null, null, null, null, null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testNullFieldValue() {
        TestQuery testQuery = new TestQuery(null, null, null, null, null, null, null, null, null, null, null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testMultipleConditions() {
        TestQuery testQuery = new TestQuery("John", 18, 100, "active", "@example.com",
                "123", Arrays.asList("admin"), "test", null, "value", null);
        Query query = QueryUtil.getQuery(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testQueryAllWithoutDeletedAtFilter() {
        TestQuery testQuery = new TestQuery("John", 18, 100, "active", "@example.com",
                "123", Arrays.asList("admin"), "test", null, "value", null);
        Query query = QueryUtil.getQueryAll(testQuery);
        assertNotNull(query);
        Criteria criteria = (Criteria) query.getCriteria().orElse(Criteria.empty());
        assertNotNull(criteria);
    }

    @Test
    void testIsBlankWithNull() {
        assertTrue(QueryUtil.isBlank(null));
    }

    @Test
    void testIsBlankWithEmptyString() {
        assertTrue(QueryUtil.isBlank(""));
    }

    @Test
    void testIsBlankWithWhitespace() {
        assertTrue(QueryUtil.isBlank("   "));
    }

    @Test
    void testIsBlankWithValidString() {
        assertFalse(QueryUtil.isBlank("test"));
    }

    @Test
    void testIsBlankWithMixedWhitespace() {
        assertFalse(QueryUtil.isBlank("  test  "));
    }
}
