import { createServer } from 'vite'
import { chromium } from 'playwright'

const port = Number(process.env.MINI_VISUAL_PORT ?? 4180)
const server = await createServer({ root: process.cwd(), server: { host: '127.0.0.1', port, strictPort: true } })
await server.listen()

const browser = await chromium.launch({ headless: true })
const page = await browser.newPage({ viewport: { width: 420, height: 820 }, deviceScaleFactor: 1 })
const errors = []
page.on('console', (message) => { if (message.type() === 'error') errors.push(message.text()) })

const projectId = '019b0000-0000-7000-8000-000000000101'
const expert = {
  id: '019b0000-0000-7000-8000-000000000102', slug: 'product-manager', category: 'product', categoryName: '产品',
  name: '产品经理', description: '负责需求分析、路线规划和产品交付。', emoji: '🧭', color: '#165DFF',
}
const workspace = {
  project: { id: projectId, name: '森林项目', identifier: 'forest', icon: 'folder', background: '#165DFF', description: '让项目计划、资料和 AI 协作保持在同一条线上。', initials: '森林', unreadCount: 0 },
  channels: [],
  tags: [{ id: 'tag-product', name: '产品' }, { id: 'tag-design', name: '设计' }],
  recentSessions: [],
  inbox: [],
  tasks: [
    { id: 'task-1', projectId, title: '整理产品路线', summary: '确认下一阶段交付范围。', completed: false, owner: '张明', due: null, createdAt: '今天 09:00', completedAt: null, tagId: 'tag-product', tag: '产品' },
    { id: 'task-2', projectId, title: '检查迷你布局', summary: '验证窄屏下的导航和滚动。', completed: false, owner: '张明', due: null, createdAt: '今天 10:00', completedAt: null, tagId: 'tag-design', tag: '设计' },
  ],
  aiSessions: [{ id: 'old-session', projectId, title: '梳理版本计划', summary: '项目会话', updatedAt: '今天', references: [] }],
  notesSources: [
    { id: 'note-1', projectId, kind: 'note', title: '版本规划', updatedAt: '今天', tag: '产品', source: '项目笔记' },
    { id: 'source-1', projectId, kind: 'file', title: '需求说明.pdf', updatedAt: '昨天', tag: '资料', source: '上传文件' },
  ],
  cronPlans: [{ id: 'cron-1', projectId, title: '每周复盘', schedule: '0 17 * * 5', nextRun: null, enabled: true, lastResult: '', owner: '张明' }],
}

await page.route('http://localhost:9150/api/v1/**', async (route) => {
  const request = route.request()
  const path = new URL(request.url()).pathname
  if (path === '/api/v1/status') return route.fulfill({ json: { status: 'unavailable' } })
  if (path === '/api/v1/auth/login') return route.fulfill({ json: { token: 'mini-token' } })
  if (path === '/api/v1/projects') {
    if (request.method() === 'POST') return route.fulfill({ status: 201, json: workspace.project })
    return route.fulfill({ json: [workspace.project] })
  }
  if (path === `/api/v1/projects/${projectId}/workspace`) return route.fulfill({ json: workspace })
  if (path === '/api/v1/ai-experts') return route.fulfill({ json: [expert, { ...expert, id: 'expert-2', name: 'UI 设计师', category: 'design', categoryName: '设计', emoji: '🎨', color: '#722ED1' }] })
  if (path === `/api/v1/projects/${projectId}/ai-sessions`) {
    if (request.method() === 'POST') {
      const input = request.postDataJSON()
      return route.fulfill({ status: 201, json: { id: 'session-new', projectId, title: input.title, context: input.context, status: 'ready', expert, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() } })
    }
    return route.fulfill({ json: [{ id: 'session-1', projectId, title: '梳理版本计划', context: '下一步怎么安排', status: 'ready', expert, createdAt: '2026-07-22T10:00:00Z', updatedAt: '2026-07-22T10:00:00Z' }] })
  }
  if (path.includes('/tasks/') && request.method() === 'PATCH') return route.fulfill({ json: {} })
  if (path.endsWith('/tasks') && request.method() === 'POST') return route.fulfill({ status: 201, json: {} })
  if (path.endsWith('/cron-plans') && request.method() === 'POST') return route.fulfill({ status: 201, json: {} })
  return route.fulfill({ status: 404, json: { error: { code: 'not_found', message: '未配置的视觉检查接口' } } })
})

await page.goto(`http://127.0.0.1:${port}/`, { waitUntil: 'networkidle' })
await page.waitForSelector('.mini-connection.offline')
const offlineConnection = await page.locator('.mini-connection').evaluate((element) => ({
  text: element.textContent,
  borderColor: getComputedStyle(element).borderColor,
}))
await page.screenshot({ path: 'test-results/mini-login.png', fullPage: true })
const loginDefaults = await page.locator('.login-note input').evaluateAll((inputs) => inputs.map((input) => input.value))
await page.locator('.login-note input').nth(2).press('Enter')
await page.waitForSelector('.mini-shell')
await page.waitForTimeout(400)
await page.screenshot({ path: 'test-results/mini-home-right.png', fullPage: true })

const home = await page.evaluate(() => ({
  width: document.querySelector('.mini-shell')?.getBoundingClientRect().width,
  navCount: document.querySelectorAll('.mini-nav button').length,
  dock: document.documentElement.dataset.dock,
  overflowX: document.documentElement.scrollWidth > document.documentElement.clientWidth,
  title: document.querySelector('.page-intro h4')?.textContent ?? '',
}))

await page.getByRole('button', { name: '停靠左侧' }).click()
const leftDock = await page.evaluate(() => document.documentElement.dataset.dock)

await page.getByRole('button', { name: '计划', exact: true }).click()
await page.getByRole('button', { name: '设计', exact: true }).click()
const tasks = await page.evaluate(() => ({
  count: document.querySelectorAll('.task-note').length,
  title: document.querySelector('.task-note strong')?.textContent ?? '',
}))
await page.screenshot({ path: 'test-results/mini-tasks.png', fullPage: true })

await page.getByRole('button', { name: '资料', exact: true }).click()
const notes = await page.locator('.source-note').count()

await page.getByRole('button', { name: 'AI', exact: true }).click()
await page.getByRole('button', { name: /产品经理/ }).click()
await page.locator('.mini-composer textarea').fill('请给出下一步计划')
const sendEnabled = await page.getByRole('button', { name: '开始会话' }).isEnabled()
await page.screenshot({ path: 'test-results/mini-ai.png', fullPage: true })

await browser.close()
await server.close()

const failures = []
if (!offlineConnection.text?.includes('连接异常') || offlineConnection.borderColor !== 'rgb(245, 63, 63)') failures.push(`offline connection must be red: ${JSON.stringify(offlineConnection)}`)
if (loginDefaults[1] !== 'demo@senlin.ai' || loginDefaults[2] !== 'password123') failures.push(`login defaults failed: ${JSON.stringify(loginDefaults)}`)
if (errors.length) failures.push(`console errors: ${errors.join('; ')}`)
if (home.width !== 420) failures.push(`expected 420px shell, got ${home.width}`)
if (home.navCount !== 5) failures.push(`expected five top navigation items, got ${home.navCount}`)
if (home.dock !== 'right' || leftDock !== 'left') failures.push(`dock state failed: right=${home.dock}, left=${leftDock}`)
if (home.overflowX) failures.push('mini client has horizontal overflow')
if (home.title !== '森林项目') failures.push(`project overview missing, got ${home.title}`)
if (tasks.count !== 1 || tasks.title !== '检查迷你布局') failures.push(`task tag filtering failed: ${JSON.stringify(tasks)}`)
if (notes !== 2) failures.push(`expected two note cards, got ${notes}`)
if (!sendEnabled) failures.push('AI composer must enable after selecting an expert and entering a prompt')

console.log(JSON.stringify({ home, leftDock, tasks, notes, sendEnabled, errors }, null, 2))
if (failures.length) throw new Error(failures.join('\n'))
