import test from 'node:test'
import assert from 'node:assert/strict'
import { buildAppModuleGraph } from './appModuleGraph.js'

test('buildAppModuleGraph creates a thesis-style module hierarchy from menus', () => {
  const graph = buildAppModuleGraph({
    roles: [
      { code: 'reader', name: '读者', description: '前台用户' },
      { code: 'admin', name: '管理员', description: '后台运营' }
    ],
    frontendMenus: [
      {
        code: 'catalog',
        name: '图书目录',
        path: '/catalog',
        requiresLogin: false,
        visibleRoles: [],
        dataScope: 'PUBLIC'
      },
      {
        code: 'my_borrows',
        name: '我的借阅',
        path: '/my-borrows',
        requiresLogin: true,
        visibleRoles: ['reader'],
        dataScope: 'CURRENT_USER'
      }
    ],
    adminMenus: [
      {
        code: 'book_admin',
        name: '图书管理',
        path: '/admin/books',
        requiresLogin: true,
        visibleRoles: ['admin'],
        dataScope: 'ROLE'
      }
    ]
  })

  assert.equal(graph.title, '系统模块设计')
  assert.deepEqual(
    graph.groups.map((group) => ({ key: group.key, title: group.title, childIds: group.childIds })),
    [
      { key: 'admin', title: '管理员端', childIds: ['admin:book_admin'] },
      { key: 'frontend', title: '普通用户端', childIds: ['frontend:catalog', 'frontend:my_borrows'] }
    ]
  )

  assert.deepEqual(
    graph.nodes.map((node) => ({ id: node.id, title: node.title, kind: node.kind, lane: node.lane })),
    [
      { id: 'root', title: '系统模块设计', kind: 'root', lane: 'root' },
      { id: 'group:admin', title: '管理员端', kind: 'group', lane: 'admin' },
      { id: 'admin:book_admin', title: '图书管理', kind: 'module', lane: 'admin' },
      { id: 'group:frontend', title: '普通用户端', kind: 'group', lane: 'frontend' },
      { id: 'frontend:catalog', title: '图书目录', kind: 'module', lane: 'frontend' },
      { id: 'frontend:my_borrows', title: '我的借阅', kind: 'module', lane: 'frontend' }
    ]
  )

  assert.deepEqual(
    graph.edges.map((edge) => ({ source: edge.source, target: edge.target })),
    [
      { source: 'root', target: 'group:admin' },
      { source: 'group:admin', target: 'admin:book_admin' },
      { source: 'root', target: 'group:frontend' },
      { source: 'group:frontend', target: 'frontend:catalog' },
      { source: 'group:frontend', target: 'frontend:my_borrows' }
    ]
  )
})

test('buildAppModuleGraph keeps frontend-only projects centered and exportable', () => {
  const graph = buildAppModuleGraph({
    roles: [],
    frontendMenus: [
      {
        code: 'profile',
        name: '个人中心',
        path: '/profile',
        requiresLogin: true,
        visibleRoles: [],
        dataScope: 'CURRENT_USER'
      }
    ],
    adminMenus: []
  })

  assert.deepEqual(graph.groups.map((group) => group.key), ['frontend'])
  assert.equal(graph.nodes[0].id, 'root')
  assert.equal(graph.nodes[1].id, 'group:frontend')
  assert.equal(graph.nodes[2].id, 'frontend:profile')
  assert.equal(graph.nodes[2].vertical, true)
  assert.equal(graph.edges[0].source, 'root')
  assert.equal(graph.edges[0].target, 'group:frontend')
  assert.equal(graph.edges[1].source, 'group:frontend')
  assert.equal(graph.edges[1].target, 'frontend:profile')
})

test('buildAppModuleGraph uses the project name as the root title', () => {
  const graph = buildAppModuleGraph({
    frontendMenus: [
      {
        code: 'catalog',
        name: '图书目录'
      }
    ],
    adminMenus: []
  }, {
    projectName: '图书借阅系统'
  })

  assert.equal(graph.title, '图书借阅系统')
  assert.equal(graph.nodes[0].title, '图书借阅系统')
})

test('buildAppModuleGraph skips invalid legacy menus while preserving code-only menus', () => {
  const graph = buildAppModuleGraph({
    adminMenus: [
      null,
      {},
      { name: '  ' },
      { code: 'settings' }
    ],
    frontendMenus: []
  })

  assert.deepEqual(graph.groups.map((group) => group.childIds), [['admin:settings']])
  assert.equal(graph.nodes.find((node) => node.id === 'admin:settings').title, 'settings')
})

test('buildAppModuleGraph accepts a normalized outline source', () => {
  const graph = buildAppModuleGraph({
    title: '学生社团管理系统',
    groups: [
      { title: '管理员端', items: [{ title: '用户管理' }, { title: '社团管理' }] },
      { title: '普通用户端', items: [{ title: '社团浏览' }] }
    ]
  })

  assert.equal(graph.title, '学生社团管理系统')
  assert.deepEqual(
    graph.groups.map((group) => ({ key: group.key, title: group.title, childIds: group.childIds })),
    [
      { key: 'group_1', title: '管理员端', childIds: ['group_1:module_1', 'group_1:module_2'] },
      { key: 'group_2', title: '普通用户端', childIds: ['group_2:module_1'] }
    ]
  )
  assert.equal(graph.nodes.find((node) => node.id === 'group_1:module_1').title, '用户管理')
})

test('buildAppModuleGraph density options change spacing predictably', () => {
  const outline = {
    title: '学生社团管理系统',
    groups: [
      { title: '管理员端', items: [{ title: '用户管理' }, { title: '社团管理' }, { title: '活动管理' }] },
      { title: '普通用户端', items: [{ title: '社团浏览' }, { title: '活动报名' }, { title: '个人中心' }] }
    ]
  }

  const compact = buildAppModuleGraph(outline, { density: 'compact' })
  const relaxed = buildAppModuleGraph(outline, { density: 'relaxed' })

  assert.equal(compact.options.density, 'compact')
  assert.equal(relaxed.options.density, 'relaxed')
  assert.ok(relaxed.canvas.width > compact.canvas.width)
  assert.ok(relaxed.nodes.find((node) => node.kind === 'module').height > compact.nodes.find((node) => node.kind === 'module').height)
})

test('buildAppModuleGraph font size option is stored on graph and nodes', () => {
  const graph = buildAppModuleGraph({
    title: '学生社团管理系统',
    groups: [{ title: '管理员端', items: [{ title: '用户管理' }] }]
  }, {
    fontSize: 'large'
  })

  assert.equal(graph.options.fontSize, 'large')
  assert.equal(graph.nodes.find((node) => node.kind === 'module').fontSize, 18)
  assert.equal(graph.nodes.find((node) => node.kind === 'root').fontSize, 19)
})

test('buildAppModuleGraph vertical direction produces a valid graph', () => {
  const graph = buildAppModuleGraph({
    title: '学生社团管理系统',
    groups: [
      { title: '管理员端', items: [{ title: '用户管理' }] },
      { title: '普通用户端', items: [{ title: '社团浏览' }] }
    ]
  }, {
    direction: 'vertical'
  })

  assert.equal(graph.options.direction, 'vertical')
  assert.equal(graph.nodes[0].id, 'root')
  assert.equal(graph.edges.length, 4)
  assert.ok(graph.canvas.height > 420)
})
