/**
 * 管理后台冒烟测试 — IIS部署环境
 *
 * 运行方式：
 *   cd frontend
 *   npx playwright test e2e/smoke-iis.spec.ts --project=chromium
 *
 * 断言标准：严格检查数据内容，禁止只检查元素存在
 */
import { test, expect, type Page } from '@playwright/test'

// === 登录辅助函数 ===
async function login(page: Page) {
  // 直接用完整URL，不依赖baseURL
  await page.goto('http://127.0.0.1/admin/login')
  await page.waitForLoadState('networkidle')
  // 等待登录表单渲染
  await page.waitForSelector('input', { timeout: 10000 })
  // 用CSS选择器定位：第一个input是用户名，第二个是密码
  const inputs = page.locator('input')
  await inputs.nth(0).fill('admin')
  await inputs.nth(1).fill('admin123')
  await page.locator('button').last().click()
  await page.waitForURL(/\/(dashboard|admin\/?$)/, { timeout: 15000 })
}

// === 辅助：断言文本不为空且非占位符 ===
function assertValidValue(text: string | null, label: string) {
  expect(text, `${label} 不应为null`).toBeTruthy()
  const trimmed = text!.trim()
  expect(trimmed, `${label} 不应为空字符串`).not.toBe('')
  expect(trimmed, `${label} 不应为占位符"-"`).not.toBe('-')
  expect(trimmed, `${label} 不应为占位符"--"`).not.toBe('--')
  expect(trimmed, `${label} 不应为"undefined"`).not.toBe('undefined')
  expect(trimmed, `${label} 不应为"null"`).not.toBe('null')
}

// ========================
// 登录测试
// ========================
test.describe('登录', () => {
  test('登录成功跳转到仪表盘', async ({ page }) => {
    await login(page)
    // 断言：URL包含dashboard
    expect(page.url()).toMatch(/dashboard/)
    // 断言：侧边栏有"仪表盘"菜单项
    await expect(page.getByRole('menuitem', { name: '仪表盘' })).toBeVisible()
  })
})

// ========================
// 仪表盘
// ========================
test.describe('仪表盘', () => {
  test.beforeEach(async ({ page }) => {
    await login(page)
    // 确保在仪表盘页面
    if (!page.url().includes('dashboard')) {
      await page.goto('http://127.0.0.1/admin/dashboard')
    }
    // 等待数据加载
    await page.waitForTimeout(2000)
  })

  test('统计卡片有数值', async ({ page }) => {
    // 找到所有卡片区域，检查数值部分不为空
    const cards = page.locator('.el-card')
    const cardCount = await cards.count()
    expect(cardCount, '仪表盘应该有统计卡片').toBeGreaterThan(0)

    // 检查每个卡片内的数值区域
    for (let i = 0; i < cardCount; i++) {
      const card = cards.nth(i)
      // 卡片内的数值通常在较大的字体div中
      const valueEl = card.locator('div').filter({ hasText: /^\d/ }).first()
      if (await valueEl.isVisible()) {
        const text = await valueEl.textContent()
        // 数值应该包含数字
        expect(text, `第${i + 1}个卡片应该有数值`).toMatch(/\d/)
      }
    }
  })

  test('采集服务状态显示正常', async ({ page }) => {
    // 检查采集服务状态区域
    const statusArea = page.locator('text=采集服务')
    if (await statusArea.isVisible()) {
      // 状态文本不应为空
      const statusText = await page.locator('.el-tag').first().textContent()
      assertValidValue(statusText, '采集服务状态')
    }
  })
})

// ========================
// 产量报表
// ========================
test.describe('产量报表', () => {
  test.beforeEach(async ({ page }) => {
    await login(page)
    await page.goto('http://127.0.0.1/admin/production')
    // 等待页面数据加载
    await page.waitForTimeout(2000)
  })

  test('默认加载今天数据', async ({ page }) => {
    // 检查日期选择器显示今天的日期
    const today = new Date()
    const dateStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`
    const dateInput = page.locator('input[placeholder]').first()
    const inputValue = await dateInput.inputValue()
    expect(inputValue, `日期选择器应显示今天 ${dateStr}`).toContain(dateStr.slice(0, 7)) // 至少年月匹配

    // 检查表格有数据
    const rows = page.locator('.el-table__body-wrapper .el-table__row')
    const rowCount = await rows.count()
    expect(rowCount, '产量报表应默认有数据').toBeGreaterThan(0)
  })

  test('汇总卡片有数值', async ({ page }) => {
    // 检查4个卡片：总产量、运行机床、切削总时、平均产量
    const cardLabels = ['总产量', '运行机床', '切削总时', '平均产量']
    for (const label of cardLabels) {
      // 找到标签文本所在的卡片
      const labelEl = page.locator(`text=${label}`).first()
      await expect(labelEl, `"${label}"标签应可见`).toBeVisible()
      // 同一个卡片内的数值（紧跟标签的大字div）
      const card = labelEl.locator('..').locator('..')
      const valueDiv = card.locator('div').last()
      const valueText = await valueDiv.textContent()
      assertValidValue(valueText, `"${label}"的数值`)
    }
  })

  test('表格数据列有值', async ({ page }) => {
    const rows = page.locator('.el-table__body-wrapper .el-table__row')
    const rowCount = await rows.count()
    expect(rowCount, '表格应有数据行').toBeGreaterThan(0)

    // 检查第一行的关键列
    const firstRow = rows.first()
    const cells = firstRow.locator('td .cell')

    // 日期列（第1列）
    const dateText = await cells.nth(0).textContent()
    assertValidValue(dateText, '表格第1行日期列')

    // 机床名列（第2列）
    const machineText = await cells.nth(1).textContent()
    assertValidValue(machineText, '表格第1行机床名列')

    // 产量列（第4列）
    const qtyText = await cells.nth(3).textContent()
    assertValidValue(qtyText, '表格第1行产量列')
  })

  test('车间下拉框有选项且筛选生效', async ({ page }) => {
    // 1. 记录当前表格行数
    const rowsBefore = page.locator('.el-table__body-wrapper .el-table__row')
    const countBefore = await rowsBefore.count()

    // 2. 点击车间下拉框展开（点击外层wrapper）
    const workshopSelect = page.locator('.el-form-item').filter({ hasText: '车间' }).locator('.el-select')
    await workshopSelect.click()
    await page.waitForTimeout(500)

    // 3. 断言：下拉列表中有选项
    const options = page.locator('.el-select-dropdown__item:visible')
    await expect(options.first(), '车间下拉框应有选项').toBeVisible()
    const optionCount = await options.count()
    expect(optionCount, '车间下拉框选项数量应>=1').toBeGreaterThanOrEqual(1)

    // 4. 选择第一个选项
    await options.first().click()
    await page.waitForTimeout(300)

    // 5. 点击查询按钮
    await page.getByRole('button', { name: '查询' }).click()
    await page.waitForTimeout(2000)

    // 6. 断言：表格有数据（筛选后仍应有数据）
    const rowsAfter = page.locator('.el-table__body-wrapper .el-table__row')
    const countAfter = await rowsAfter.count()
    expect(countAfter, '筛选后表格应有数据').toBeGreaterThan(0)
  })

  test('机床下拉框有选项', async ({ page }) => {
    const machineSelect = page.locator('.el-form-item').filter({ hasText: '机床' }).locator('.el-select')
    await machineSelect.click()
    await page.waitForTimeout(500)

    const options = page.locator('.el-select-dropdown__item:visible')
    await expect(options.first(), '机床下拉框应有选项').toBeVisible()
    const count = await options.count()
    expect(count, '机床下拉框选项数量应>=1').toBeGreaterThanOrEqual(1)

    // 关闭下拉框
    await page.keyboard.press('Escape')
  })

  test('工人下拉框有选项', async ({ page }) => {
    const workerSelect = page.locator('.el-form-item').filter({ hasText: '工人' }).locator('.el-select')
    await workerSelect.click()
    await page.waitForTimeout(500)

    const options = page.locator('.el-select-dropdown__item:visible')
    await expect(options.first(), '工人下拉框应有选项').toBeVisible()
    const count = await options.count()
    expect(count, '工人下拉框选项数量应>=1').toBeGreaterThanOrEqual(1)

    // 关闭下拉框
    await page.keyboard.press('Escape')
  })

  test('重置按钮清空筛选', async ({ page }) => {
    // 先选择一个车间
    const workshopSelect = page.locator('.el-form-item').filter({ hasText: '车间' }).locator('.el-select')
    await workshopSelect.click()
    await page.waitForTimeout(500)
    await page.locator('.el-select-dropdown__item:visible').first().click()
    await page.waitForTimeout(300)

    // 点重置
    await page.getByRole('button', { name: '重置' }).click()
    await page.waitForTimeout(1000)

    // 断言：车间下拉框恢复占位符
    const placeholder = workshopSelect.locator('.el-select__placeholder')
    const placeholderText = await placeholder.textContent()
    expect(placeholderText, '重置后车间下拉框应显示占位符').toContain('请选择')
  })

  test('修正弹窗能打开', async ({ page }) => {
    // 点击第一行的"修正"按钮
    const adjustBtn = page.locator('.el-table__body-wrapper .el-table__row').first().getByRole('button', { name: '修正' })
    await adjustBtn.click()
    await page.waitForTimeout(500)

    // 断言：弹窗出现，标题包含"修正"
    const dialog = page.locator('.el-dialog:visible')
    await expect(dialog, '修正弹窗应可见').toBeVisible()
    const title = await dialog.locator('.el-dialog__title').textContent()
    expect(title, '弹窗标题应包含"修正"').toContain('修正')

    // 断言：当前产量输入框有值
    const input = dialog.locator('input').first()
    const inputValue = await input.inputValue()
    expect(inputValue, '当前产量输入框应有初始值').toBeTruthy()

    // 关闭弹窗
    await dialog.locator('.el-dialog__headerbtn').click()
  })

  test('修正历史弹窗能打开', async ({ page }) => {
    const historyBtn = page.locator('.el-table__body-wrapper .el-table__row').first().getByRole('button', { name: '修正历史' })
    await historyBtn.click()
    await page.waitForTimeout(500)

    // 断言：弹窗出现
    const dialog = page.locator('.el-dialog:visible')
    await expect(dialog, '修正历史弹窗应可见').toBeVisible()
    const title = await dialog.locator('.el-dialog__title').textContent()
    expect(title, '弹窗标题应包含"修正历史"').toContain('修正历史')

    // 关闭弹窗
    await dialog.locator('.el-dialog__headerbtn').click()
  })

  // === 新增：表格所有列验证 ===
  test('表格所有列有数据（运行时间、切削时间、日状态、修正标记）', async ({ page }) => {
    const rows = page.locator('.el-table__body-wrapper .el-table__row')
    expect(await rows.count(), '表格应有数据行').toBeGreaterThan(0)
    const cells = rows.first().locator('td .cell')

    // 运行时间列（第5列）— 应有数值，不为空
    const runTime = await cells.nth(4).textContent()
    assertValidValue(runTime, '运行时间列')

    // 切削时间列（第6列）— 应有数值，不为空
    const cutTime = await cells.nth(5).textContent()
    assertValidValue(cutTime, '切削时间列')

    // 日状态列（第7列）— 应为"正常"或"缺失"或"离线"
    const status = await cells.nth(6).textContent()
    expect(status, '日状态列应有值').toBeTruthy()
    const validStatuses = ['正常', '缺失', '离线']
    expect(validStatuses, `日状态应为已知值，实际: ${status?.trim()}`).toContain(status?.trim())

    // 修正列（第8列）— 应为"✓"或"-"
    const adjusted = await cells.nth(7).textContent()
    expect(adjusted, '修正列应有值').toBeTruthy()
  })

  // === 新增：分页切换 ===
  test('分页切换有效', async ({ page }) => {
    // 检查分页组件
    const pagination = page.locator('.el-pagination')
    await expect(pagination, '分页组件应可见').toBeVisible()

    // 检查总数
    const totalText = await pagination.locator('.el-pagination__total').textContent()
    expect(totalText, '分页应显示总数').toContain('条')

    // 如果有多页，切换到第2页
    const page2Btn = pagination.locator('.el-pager > li').nth(1)
    if (await page2Btn.isVisible()) {
      // 记录第一页第一行机床名
      const row1Before = await page.locator('.el-table__body-wrapper .el-table__row').first().locator('td .cell').nth(1).textContent()

      // 点击第2页
      await page2Btn.click()
      await page.waitForTimeout(1500)

      // 验证：第2页高亮
      await expect(page2Btn, '第2页应高亮').toHaveClass(/is-active/)

      // 验证：表格第一行机床名变化了（不同页数据不同）
      const row1After = await page.locator('.el-table__body-wrapper .el-table__row').first().locator('td .cell').nth(1).textContent()
      expect(row1After, '切页后第一行数据应不同').toBeTruthy()
    }
  })

  // === 新增：日期范围筛选 ===
  test('日期范围筛选生效', async ({ page }) => {
    // 记录当前总数
    const totalBefore = await page.locator('.el-pagination__total').textContent()

    // 用JS直接修改日期范围（选一个未来日期确保无数据）
    await page.evaluate(() => {
      // 找到Vue实例并修改日期
      const inputs = document.querySelectorAll('.el-date-editor input')
      if (inputs.length >= 2) {
        // 模拟选2099-01-01，一个不可能有数据的日期
        const evt = new Event('input', { bubbles: true })
        ;(inputs[0] as HTMLInputElement).value = '2099-01-01'
        inputs[0].dispatchEvent(evt)
        ;(inputs[1] as HTMLInputElement).value = '2099-01-01'
        inputs[1].dispatchEvent(evt)
      }
    })
    // 点查询
    await page.locator('button:has-text("查询")').click()
    await page.waitForTimeout(2000)

    // 验证：2099年不应该有数据，表格行数应为0或显示空状态
    const rows = page.locator('.el-table__body-wrapper .el-table__row')
    const rowCount = await rows.count()
    expect(rowCount, '2099年不应该有产量数据').toBe(0)
  })

  // === 新增：程序名文本筛选 ===
  test('程序名筛选生效', async ({ page }) => {
    // 先看第一行的程序名
    const firstProgramCell = page.locator('.el-table__body-wrapper .el-table__row').first().locator('td .cell').nth(2)
    const programName = await firstProgramCell.textContent()
    assertValidValue(programName, '第一行程序名列')

    // 输入程序名筛选
    const programInput = page.locator('input[placeholder="输入程序名"]')
    await programInput.fill(programName!.trim())
    await page.locator('button:has-text("查询")').click()
    await page.waitForTimeout(2000)

    // 验证：表格数据应包含该程序名
    const rows = page.locator('.el-table__body-wrapper .el-table__row')
    const rowCount = await rows.count()
    expect(rowCount, `筛选"${programName?.trim()}"后应有数据`).toBeGreaterThan(0)

    // 验证：每行的程序名列都包含筛选关键词
    for (let i = 0; i < Math.min(rowCount, 5); i++) {
      const cell = rows.nth(i).locator('td .cell').nth(2)
      const text = await cell.textContent()
      expect(text?.trim(), `第${i + 1}行程序名应包含筛选关键词`).toContain(programName!.trim())
    }
  })

  // === 新增：API返回值 vs 页面显示值对账 ===
  test('汇总卡片数值与API返回一致', async ({ page }) => {
    // 通过浏览器fetch调API，拿到实际返回值
    const apiData = await page.evaluate(async () => {
      const token = localStorage.getItem('token')
      const today = new Date().toISOString().slice(0, 10)
      const res = await fetch(`/api/admin/production/daily-summary?date=${today}`, {
        headers: { Authorization: `Bearer ${token}` }
      })
      const json = await res.json()
      return json.data
    })

    expect(apiData, 'API应返回数据').toBeTruthy()

    // 验证总产量卡片
    const totalQtyLabel = page.locator('text=总产量').first()
    if (await totalQtyLabel.isVisible()) {
      const card = totalQtyLabel.locator('..').locator('..')
      const valueDiv = card.locator('div').last()
      const displayText = await valueDiv.textContent()
      const displayNum = parseInt(displayText!.trim().replace(/,/g, ''), 10)
      const apiNum = apiData.totalQuantity
      expect(displayNum, `页面总产量${displayNum}应与API返回${apiNum}一致`).toBe(apiNum)
    }

    // 验证运行机床卡片
    const machineLabel = page.locator('text=运行机床').first()
    if (await machineLabel.isVisible()) {
      const card = machineLabel.locator('..').locator('..')
      const valueDiv = card.locator('div').last()
      const displayText = await valueDiv.textContent()
      const displayNum = parseInt(displayText!.trim(), 10)
      const apiNum = apiData.activeMachineCount
      expect(displayNum, `页面运行机床${displayNum}应与API返回${apiNum}一致`).toBe(apiNum)
    }
  })

  // === 新增：下拉框选项值验证（前后端字段映射） ===
  test('下拉框选项文本和值都有效', async ({ page }) => {
    // 展开车间下拉框
    const workshopSelect = page.locator('.el-form-item').filter({ hasText: '车间' }).locator('.el-select')
    await workshopSelect.click()
    await page.waitForTimeout(500)

    const options = page.locator('.el-select-dropdown__item:visible')
    const count = await options.count()
    expect(count, '车间下拉框应有选项').toBeGreaterThan(0)

    // 验证每个选项的文本不是空/undefined/null
    for (let i = 0; i < Math.min(count, 5); i++) {
      const text = await options.nth(i).textContent()
      assertValidValue(text, `车间第${i + 1}个选项`)
    }

    // 关闭下拉框
    await page.keyboard.press('Escape')
  })

  // === 新增：修正弹窗提交闭环 ===
  test('修正弹窗提交后列表刷新', async ({ page }) => {
    // 获取第一行当前产量
    const firstRow = page.locator('.el-table__body-wrapper .el-table__row').first()
    const qtyCell = firstRow.locator('td .cell').nth(3)
    const qtyBefore = await qtyCell.textContent()

    // 点击修正按钮
    await firstRow.getByRole('button', { name: '修正' }).click()
    await page.waitForTimeout(500)

    const dialog = page.locator('.el-dialog:visible')
    await expect(dialog).toBeVisible()

    // 读取当前产量
    const currentInput = dialog.locator('input').first()
    const currentValue = await currentInput.inputValue()
    expect(currentValue, '当前产量应有值').toBeTruthy()

    // 修改为新值（原值+1）
    const newQty = parseInt(currentValue, 10) + 1
    const newQtyInput = dialog.locator('input').nth(1)
    // 清空并输入新值
    await newQtyInput.fill(String(newQty))

    // 填写修正原因
    const reasonTextarea = dialog.locator('textarea')
    await reasonTextarea.fill('E2E自动化测试修正')

    // 监听confirm弹窗并自动确认
    page.on('dialog', async dialog => {
      await dialog.accept()
    })

    // 点确认修正
    await dialog.locator('button:has-text("确认修正")').click()
    await page.waitForTimeout(2000)

    // 验证：弹窗关闭
    await expect(page.locator('.el-dialog:visible'), '修正后弹窗应关闭').toHaveCount(0)

    // 验证：表格刷新了（行数>0说明没崩溃）
    const rows = page.locator('.el-table__body-wrapper .el-table__row')
    expect(await rows.count(), '修正后表格应有数据').toBeGreaterThan(0)
  })
})

// ========================
// 设备管理
// ========================
test.describe('设备管理', () => {
  test.beforeEach(async ({ page }) => {
    await login(page)
    await page.goto('http://127.0.0.1/admin/machine')
    await page.waitForTimeout(2000)
  })

  test('机床列表有数据', async ({ page }) => {
    const rows = page.locator('.el-table__body-wrapper .el-table__row')
    const rowCount = await rows.count()
    expect(rowCount, '设备管理表格应有数据行').toBeGreaterThan(0)
  })
})
