#include <string.h>

#include "test_common.h"

#include "../src/Drv/pages/menu/view.h"
#include "../src/Drv/pages/menu/model.h"
#include "../src/Drv/pages/menu/page.h"

/* -------------------------------------------------------------------------
 * 函数名: main
 * 功能:
 *   覆盖菜单模块的白盒/黑盒关键能力，验证：
 *   1) Model 初始化与辅助函数
 *   2) 菜单树构建与显示名称装饰
 *   3) View 初始化后的端口与接口绑定
 *   4) MenuPage 生命周期入口是否完整绑定
 *
 * 参数:
 *   无
 *
 * 返回值:
 *   - 0 : 测试通过
 * ------------------------------------------------------------------------- */
int main(void)
{
    /* 用于 MenuView_CharLenCal / Position 相关白盒测试的临时数组 */
    tagPMenuItem first[4] = {0};
    tagPMenuItem index[4] = {0};
    uint8_t max_len;

    /* 页面实例：用于验证 MenuPage_GetInstance 生命周期回调绑定 */
    page_t *menuPage;

    /* 真实菜单模型对象：用于测试 MenuModel_Init 及其派生结果 */
    menu_model_t menuModel;

    /* 视图对象：用于验证 MenuView_Init 的接口与渲染端口初始化 */
    MenuView view;

    /* 自定义最小菜单树：用于单独测试 BuildTree / DecorateDisplayNames */
    tagMenuItem customItems[4];
    tagMenuItem customItems2[7];
    tagMenuModel customModelTab[4] =
    {
        {0, "Root",   "", 0, 0x0000, 0, NULL},
        {1, "ChildA", "", 0, 0x0000, 0, NULL},
        {2, "Leaf",   "", 0, 0x0000, 0, NULL},
        {1, "ChildB", "", 0, 0x0000, 0, NULL}
    };
    tagMenuModel customModelTab2[7] =
    {
        {0, "RootA", "", 0, 0x0000, 0, NULL},
        {1, "A1",    "", 0, 0x0000, 0, NULL},
        {2, "A1a",   "", 0, 0x0000, 0, NULL},
        {1, "A2",    "", 0, 0x0000, 0, NULL},
        {0, "RootB", "", 0, 0x0000, 0, NULL},
        {1, "B1",    "", 0, 0x0000, 0, NULL},
        {0, "RootC", "", 0, 0x0000, 0, NULL}
    };

    /* ---------------------------------------------------------------------
     * Case 1:
     *   测试 MenuModel_Init / MenuModel_CountTopLevel
     *   - 初始化真实菜单模型
     *   - 验证 0 级菜单数量统计结果有效
     * --------------------------------------------------------------------- */
    memset(&menuModel, 0, sizeof(menuModel));
    MenuModel_Init(&menuModel);

    /* ---------------------------------------------------------------------
     * Case 2:
     *   测试 MenuView_Utf8LenCal
     *   - 验证英文与中文字符串长度计算逻辑
     * --------------------------------------------------------------------- */
    ASSERT_EQ_INT(3, MenuModel_Utf8LenCal((uint8_t *)"ABC"));
    ASSERT_EQ_INT(2, MenuModel_Utf8LenCal((uint8_t *)"你"));

    /* ---------------------------------------------------------------------
     * Case 3:
     *   测试 MenuModel_IndexMenuItems / MenuModel_GetMenuMaxDisplayLen
     *   - 使用真实菜单模型验证 0 基序号初始化、子节点数量统计与子菜单宽度统计
     * --------------------------------------------------------------------- */
    first[0] = &menuModel.menuItems[0];
    index[0] = &menuModel.menuItems[0];
    first[1] = menuModel.menuItems[0].links.lower;
    max_len = MenuModel_GetMenuMaxDisplayLen(first[1]);
    ASSERT_TRUE(max_len > 0);
    ASSERT_EQ_INT(0, menuModel.menuItems[0].rect.wPos);
    ASSERT_EQ_INT(0, first[1]->rect.wPos);
    ASSERT_TRUE(menuModel.menuItems[0].rect.wNum > 0);
    if (first[1]->links.lower == NULL)
    {
        ASSERT_EQ_INT(0, first[1]->rect.wNum);
    }
    else
    {
        ASSERT_TRUE(first[1]->rect.wNum > 0);
    }

    /* ---------------------------------------------------------------------
     * Case 4:
     *   测试 MenuModel_DecorateDisplayNames 的真实初始化结果
     *   - 验证存在子菜单的项名称非空，并被正确用于显示
     * --------------------------------------------------------------------- */
    /* 有子菜单的项会被装饰追加 '\x10'（右箭头标记） */
    ASSERT_TRUE(((const char *)menuModel.menuItems[1].menuDef.byName)[0] != '\0');

    /* ---------------------------------------------------------------------
     * Case 5:
     *   测试 MenuModel_BuildTree
     *   - 使用自定义 4 节点菜单表验证父子、同层、闭环链路关系
     * --------------------------------------------------------------------- */
    memset(customItems, 0, sizeof(customItems));

    MenuModel_BuildTree(customItems, customModelTab, 4);
    MenuModel_IndexMenuItems(customItems, 4);
    ASSERT_TRUE(customItems[0].links.lower == &customItems[1]);
    ASSERT_TRUE(customItems[1].links.higher == &customItems[0]);
    ASSERT_TRUE(customItems[1].links.lower == &customItems[2]);
    ASSERT_TRUE(customItems[2].links.higher == &customItems[1]);
    ASSERT_TRUE(customItems[1].links.behind == &customItems[3]);
    ASSERT_TRUE(customItems[3].links.before == &customItems[1]);
    ASSERT_TRUE(customItems[3].links.higher == &customItems[0]);
    ASSERT_TRUE(customItems[3].links.behind == &customItems[1]); /* 同层闭环 */
    ASSERT_EQ_INT(0, customItems[0].rect.wPos);
    ASSERT_EQ_INT(2, customItems[0].rect.wNum);
    ASSERT_EQ_INT(0, customItems[1].rect.wPos);
    ASSERT_EQ_INT(1, customItems[1].rect.wNum);
    ASSERT_EQ_INT(1, customItems[3].rect.wPos);
    ASSERT_EQ_INT(0, customItems[3].rect.wNum);
    ASSERT_EQ_INT(0, customItems[2].rect.wPos);
    ASSERT_EQ_INT(0, customItems[2].rect.wNum);

    /* ---------------------------------------------------------------------
     * Case 5.1:
     *   强化测试 MenuModel_IndexMenuItems
     *   - 覆盖多顶层、多兄弟、跨层回退后的 0 基 wPos / wNum 统计
     * --------------------------------------------------------------------- */
    memset(customItems2, 0, sizeof(customItems2));
    MenuModel_BuildTree(customItems2, customModelTab2, 7);
    MenuModel_IndexMenuItems(customItems2, 7);
    ASSERT_EQ_INT(0, customItems2[0].rect.wPos);
    ASSERT_EQ_INT(2, customItems2[0].rect.wNum);
    ASSERT_EQ_INT(0, customItems2[1].rect.wPos);
    ASSERT_EQ_INT(1, customItems2[1].rect.wNum);
    ASSERT_EQ_INT(0, customItems2[2].rect.wPos);
    ASSERT_EQ_INT(0, customItems2[2].rect.wNum);
    ASSERT_EQ_INT(1, customItems2[3].rect.wPos);
    ASSERT_EQ_INT(0, customItems2[3].rect.wNum);
    ASSERT_EQ_INT(1, customItems2[4].rect.wPos);
    ASSERT_EQ_INT(1, customItems2[4].rect.wNum);
    ASSERT_EQ_INT(0, customItems2[5].rect.wPos);
    ASSERT_EQ_INT(0, customItems2[5].rect.wNum);
    ASSERT_EQ_INT(2, customItems2[6].rect.wPos);
    ASSERT_EQ_INT(0, customItems2[6].rect.wNum);

    /* ---------------------------------------------------------------------
     * Case 6:
     *   测试 MenuModel_DecorateDisplayNames
     *   - 验证有子节点的项追加 '\x10'
     *   - 验证叶子节点名称不被追加装饰符
     * --------------------------------------------------------------------- */
    MenuModel_DecorateDisplayNames(customItems, 4);
    ASSERT_TRUE(customItems[0].menuDef.byName[4] == '\x10');
    ASSERT_TRUE(customItems[0].menuDef.byName[5] == '\0');
    ASSERT_TRUE(customItems[1].menuDef.byName[6] == '\x10');
    ASSERT_TRUE(customItems[1].menuDef.byName[7] == '\0');
    ASSERT_TRUE(customItems[2].menuDef.byName[4] == '\0'); /* 叶子节点不追加 */

    /* ---------------------------------------------------------------------
     * Case 7:
     *   测试 MenuView_Init / MenuView_GetPortForTest
     *   - 验证 View 初始化后渲染端口、布局参数、接口函数指针均可用
     * --------------------------------------------------------------------- */
    /* View 初始化后，渲染端口派生数据和对外接口必须可用 */
    memset(&view, 0, sizeof(view));
    ASSERT_TRUE(MenuView_GetPortForTest() == NULL);
    MenuView_Init(&view);
    ASSERT_TRUE(MenuView_GetPortForTest() != NULL);
    ASSERT_TRUE(view.update_selection_new_level != NULL);
    ASSERT_TRUE(view.update_selection_same_level != NULL);
    ASSERT_TRUE(view.full_refresh != NULL);

    /* ---------------------------------------------------------------------
     * Case 8:
     *   测试 MenuPage_GetInstance
     *   - 验证页面生命周期入口已经完整绑定
     * --------------------------------------------------------------------- */
    /* 页面生命周期入口必须完整绑定，避免注册后生命周期不执行 */
    menuPage = MenuPage_GetInstance();
    ASSERT_TRUE(menuPage != NULL);
    ASSERT_TRUE(menuPage->on_create != NULL);
    ASSERT_TRUE(menuPage->on_enter != NULL);
    ASSERT_TRUE(menuPage->on_exit != NULL);
    ASSERT_TRUE(menuPage->on_destroy != NULL);
    ASSERT_TRUE(menuPage->on_event != NULL);
    ASSERT_TRUE(menuPage->on_loop != NULL);

    return 0;
}
