import { test, expect } from '@playwright/test'

import { commonPoints, getUtils, setup, tearDown } from './test-utils'
import { Coords2d } from 'lang/std/sketch'
import { KCL_DEFAULT_LENGTH } from 'lib/constants'
import { uuidv4 } from 'lib/utils'

test.beforeEach(async ({ context, page }) => {
  await setup(context, page)
})

test.afterEach(async ({ page }, testInfo) => {
  await tearDown(page, testInfo)
})

test.describe('Testing selections', () => {
  test.setTimeout(90_000)
  test('Selections work on fresh and edited sketch', async ({ page }) => {
    // Skip on windows its being weird.
    test.skip(process.platform === 'win32', 'Skip on windows')

    // tests mapping works on fresh sketch and edited sketch
    // tests using hovers which is the same as selections, because if
    // source ranges are wrong, hovers won't work
    const u = await getUtils(page)
    const PUR = 400 / 37.5 //pixeltoUnitRatio
    await page.setViewportSize({ width: 1200, height: 500 })

    await u.waitForAuthSkipAppStart()
    await u.openDebugPanel()

    const xAxisClick = () =>
      page.mouse.click(700, 253).then(() => page.waitForTimeout(100))
    const emptySpaceClick = () =>
      page.mouse.click(700, 343).then(() => page.waitForTimeout(100))
    const topHorzSegmentClick = () =>
      page.mouse.click(709, 290).then(() => page.waitForTimeout(100))
    const bottomHorzSegmentClick = () =>
      page.mouse.click(767, 396).then(() => page.waitForTimeout(100))

    await u.clearCommandLogs()
    await expect(
      page.getByRole('button', { name: 'Start Sketch' })
    ).not.toBeDisabled()
    await page.getByRole('button', { name: 'Start Sketch' }).click()

    // select a plane
    await page.mouse.click(700, 200)
    await page.waitForTimeout(700) // wait for animation

    const startXPx = 600
    await u.closeDebugPanel()
    await page.mouse.click(startXPx + PUR * 10, 500 - PUR * 10)
    await expect(page.locator('.cm-content'))
      .toHaveText(`const sketch001 = startSketchOn('XZ')
    |> startProfileAt(${commonPoints.startAt}, %)`)

    await page.waitForTimeout(100)
    await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 10)

    await expect(page.locator('.cm-content'))
      .toHaveText(`const sketch001 = startSketchOn('XZ')
    |> startProfileAt(${commonPoints.startAt}, %)
    |> line([${commonPoints.num1}, 0], %)`)

    await page.waitForTimeout(100)
    await page.mouse.click(startXPx + PUR * 20, 500 - PUR * 20)
    await expect(page.locator('.cm-content'))
      .toHaveText(`const sketch001 = startSketchOn('XZ')
    |> startProfileAt(${commonPoints.startAt}, %)
    |> line([${commonPoints.num1}, 0], %)
    |> line([0, ${commonPoints.num1 + 0.01}], %)`)
    await page.waitForTimeout(100)
    await page.mouse.click(startXPx, 500 - PUR * 20)
    await expect(page.locator('.cm-content'))
      .toHaveText(`const sketch001 = startSketchOn('XZ')
    |> startProfileAt(${commonPoints.startAt}, %)
    |> line([${commonPoints.num1}, 0], %)
    |> line([0, ${commonPoints.num1 + 0.01}], %)
    |> line([-${commonPoints.num2}, 0], %)`)

    // deselect line tool
    await page.getByRole('button', { name: 'line Line', exact: true }).click()

    await u.closeDebugPanel()
    const selectionSequence = async () => {
      await expect(page.getByTestId('hover-highlight')).not.toBeVisible()

      await page.waitForTimeout(100)
      await page.mouse.move(startXPx + PUR * 15, 500 - PUR * 10)

      await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
      // bg-yellow-300/70 is more brittle than hover-highlight, but is closer to the user experience
      // and will be an easy fix if it breaks because we change the colour
      await expect(page.locator('.bg-yellow-300\\/70')).toBeVisible()
      // check mousing off, than mousing onto another line
      await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 15) // mouse off
      await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
      await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 20) // mouse onto another line
      await expect(page.getByTestId('hover-highlight').first()).toBeVisible()

      // now check clicking works including axis

      // click a segment hold shift and click an axis, see that a relevant constraint is enabled
      await topHorzSegmentClick()
      await page.keyboard.down('Shift')
      const constrainButton = page.getByRole('button', {
        name: 'Length: open menu',
      })
      const absYButton = page.getByRole('button', { name: 'Absolute Y' })
      await constrainButton.click()
      await expect(absYButton).toBeDisabled()
      await page.waitForTimeout(100)
      await xAxisClick()
      await page.keyboard.up('Shift')
      await constrainButton.click()
      await absYButton.and(page.locator(':not([disabled])')).waitFor()
      await expect(absYButton).not.toBeDisabled()

      // clear selection by clicking on nothing
      await emptySpaceClick()

      await page.waitForTimeout(100)
      // same selection but click the axis first
      await xAxisClick()
      await constrainButton.click()
      await expect(absYButton).toBeDisabled()
      await page.keyboard.down('Shift')
      await page.waitForTimeout(100)
      await topHorzSegmentClick()
      await page.waitForTimeout(100)

      await page.keyboard.up('Shift')
      await constrainButton.click()
      await expect(absYButton).not.toBeDisabled()

      // clear selection by clicking on nothing
      await emptySpaceClick()

      // check the same selection again by putting cursor in code first then selecting axis
      await page.getByText(`  |> line([-${commonPoints.num2}, 0], %)`).click()
      await page.keyboard.down('Shift')
      await constrainButton.click()
      await expect(absYButton).toBeDisabled()
      await page.waitForTimeout(100)
      await xAxisClick()
      await page.keyboard.up('Shift')
      await constrainButton.click()
      await expect(absYButton).not.toBeDisabled()

      // clear selection by clicking on nothing
      await emptySpaceClick()

      // select segment in editor than another segment in scene and check there are two cursors
      // TODO change this back to shift click in the scene, not cmd click in the editor
      await bottomHorzSegmentClick()

      await expect(page.locator('.cm-cursor')).toHaveCount(1)

      await page.keyboard.down(
        process.platform === 'linux' ? 'Control' : 'Meta'
      )
      await page.waitForTimeout(100)
      await page.getByText(`  |> line([-${commonPoints.num2}, 0], %)`).click()

      await expect(page.locator('.cm-cursor')).toHaveCount(2)
      await page.waitForTimeout(500)
      await page.keyboard.up(process.platform === 'linux' ? 'Control' : 'Meta')

      // clear selection by clicking on nothing
      await emptySpaceClick()
    }

    await selectionSequence()

    // hovering in fresh sketch worked, lets try exiting and re-entering
    await u.openAndClearDebugPanel()
    await page.getByRole('button', { name: 'Exit Sketch' }).click()
    await page.waitForTimeout(200)
    // wait for execution done

    await u.expectCmdLog('[data-message-type="execution-done"]')
    await u.closeDebugPanel()

    // select a line, this verifies that sketches in the scene can be selected outside of sketch mode
    await topHorzSegmentClick()
    await page.waitForTimeout(100)

    // enter sketch again
    await u.doAndWaitForCmd(
      () => page.getByRole('button', { name: 'Edit Sketch' }).click(),
      'default_camera_get_settings'
    )
    await page.waitForTimeout(150)

    await page.waitForTimeout(300) // wait for animation

    await u.openAndClearDebugPanel()
    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_look_at',
        center: { x: 0, y: 0, z: 0 },
        vantage: { x: 0, y: -1378.01, z: 0 },
        up: { x: 0, y: 0, z: 1 },
      },
    })
    await page.waitForTimeout(100)
    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_get_settings',
      },
    })
    await page.waitForTimeout(100)

    await emptySpaceClick()

    await u.closeDebugPanel()

    // hover again and check it works
    await selectionSequence()
  })

  test('Solids should be select and deletable', async ({ page }) => {
    test.setTimeout(90_000)
    const u = await getUtils(page)
    await page.addInitScript(async () => {
      localStorage.setItem(
        'persistCode',
        `const sketch001 = startSketchOn('XZ')
        |> startProfileAt([-79.26, 95.04], %)
        |> line([112.54, 127.64], %, $seg02)
        |> line([170.36, -121.61], %, $seg01)
        |> lineTo([profileStartX(%), profileStartY(%)], %)
        |> close(%)
const extrude001 = extrude(50, sketch001)
const sketch005 = startSketchOn(extrude001, 'END')
  |> startProfileAt([23.24, 136.52], %)
  |> line([-8.44, 36.61], %)
  |> line([49.4, 2.05], %)
  |> line([29.69, -46.95], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const sketch003 = startSketchOn(extrude001, seg01)
  |> startProfileAt([21.23, 17.81], %)
  |> line([51.97, 21.32], %)
  |> line([4.07, -22.75], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const sketch002 = startSketchOn(extrude001, seg02)
  |> startProfileAt([-100.54, 16.99], %)
  |> line([0, 20.03], %)
  |> line([62.61, 0], %, $seg03)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude002 = extrude(50, sketch002)
const sketch004 = startSketchOn(extrude002, seg03)
  |> startProfileAt([57.07, 134.77], %)
  |> line([-4.72, 22.84], %)
  |> line([28.8, 6.71], %)
  |> line([9.19, -25.33], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude003 = extrude(20, sketch004)
const pipeLength = 40
const pipeSmallDia = 10
const pipeLargeDia = 20
const thickness = 0.5
const part009 = startSketchOn('XY')
  |> startProfileAt([pipeLargeDia - (thickness / 2), 38], %)
  |> line([thickness, 0], %)
  |> line([0, -1], %)
  |> angledLineToX({
       angle: 60,
       to: pipeSmallDia + thickness
     }, %)
  |> line([0, -pipeLength], %)
  |> angledLineToX({
       angle: -60,
       to: pipeLargeDia + thickness
     }, %)
  |> line([0, -1], %)
  |> line([-thickness, 0], %)
  |> line([0, 1], %)
  |> angledLineToX({ angle: 120, to: pipeSmallDia }, %)
  |> line([0, pipeLength], %)
  |> angledLineToX({ angle: 60, to: pipeLargeDia }, %)
  |> close(%)
const rev = revolve({ axis: 'y' }, part009)
`
      )
    }, KCL_DEFAULT_LENGTH)
    await page.setViewportSize({ width: 1000, height: 500 })
    await page.goto('/')
    await u.waitForAuthSkipAppStart()

    await u.openDebugPanel()
    await u.expectCmdLog('[data-message-type="execution-done"]')
    await u.closeDebugPanel()

    await u.openAndClearDebugPanel()
    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_look_at',
        vantage: { x: 1139.49, y: -7053, z: 8597.31 },
        center: { x: -2206.68, y: -1298.36, z: 60 },
        up: { x: 0, y: 0, z: 1 },
      },
    })
    await page.waitForTimeout(100)
    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_get_settings',
      },
    })
    await page.waitForTimeout(100)

    const revolve = { x: 646, y: 248 }
    const parentExtrude = { x: 915, y: 133 }
    const solid2d = { x: 770, y: 167 }

    // DELETE REVOLVE
    await page.mouse.click(revolve.x, revolve.y)
    await page.waitForTimeout(100)
    await expect(page.locator('.cm-activeLine')).toHaveText(
      '|> line([0, -pipeLength], %)'
    )
    await u.clearCommandLogs()
    await page.keyboard.press('Backspace')
    await u.expectCmdLog('[data-message-type="execution-done"]', 10_000)
    await page.waitForTimeout(200)

    await expect(u.codeLocator).not.toContainText(
      `const rev = revolve({ axis: 'y' }, part009)`
    )

    // DELETE PARENT EXTRUDE
    await page.mouse.click(parentExtrude.x, parentExtrude.y)
    await page.waitForTimeout(100)
    await expect(page.locator('.cm-activeLine')).toHaveText(
      '|> line([170.36, -121.61], %, $seg01)'
    )
    await u.clearCommandLogs()
    await page.keyboard.press('Backspace')
    await u.expectCmdLog('[data-message-type="execution-done"]', 10_000)
    await page.waitForTimeout(200)
    await expect(u.codeLocator).not.toContainText(
      `const extrude001 = extrude(50, sketch001)`
    )
    await expect(u.codeLocator).toContainText(`const sketch005 = startSketchOn({
       plane: {
         origin: { x: 0, y: -50, z: 0 },
         x_axis: { x: 1, y: 0, z: 0 },
         y_axis: { x: 0, y: 0, z: 1 },
         z_axis: { x: 0, y: -1, z: 0 }
       }
     })`)
    await expect(u.codeLocator).toContainText(`const sketch003 = startSketchOn({
       plane: {
         origin: { x: 116.53, y: 0, z: 163.25 },
         x_axis: { x: -0.81, y: 0, z: 0.58 },
         y_axis: { x: 0, y: -1, z: 0 },
         z_axis: { x: 0.58, y: 0, z: 0.81 }
       }
     })`)
    await expect(u.codeLocator).toContainText(`const sketch002 = startSketchOn({
       plane: {
         origin: { x: -91.74, y: 0, z: 80.89 },
         x_axis: { x: -0.66, y: 0, z: -0.75 },
         y_axis: { x: 0, y: -1, z: 0 },
         z_axis: { x: -0.75, y: 0, z: 0.66 }
       }
     })`)

    // DELETE SOLID 2D
    await page.mouse.click(solid2d.x, solid2d.y)
    await page.waitForTimeout(100)
    await expect(page.locator('.cm-activeLine')).toHaveText(
      '|> startProfileAt([23.24, 136.52], %)'
    )
    await u.clearCommandLogs()
    await page.keyboard.press('Backspace')
    await u.expectCmdLog('[data-message-type="execution-done"]', 10_000)
    await page.waitForTimeout(200)
    await expect(u.codeLocator).not.toContainText(
      `const sketch005 = startSketchOn({`
    )
  })
  test("Deleting solid that the AST mod can't handle results in a toast message", async ({
    page,
  }) => {
    const u = await getUtils(page)
    await page.addInitScript(async () => {
      localStorage.setItem(
        'persistCode',
        `const sketch001 = startSketchOn('XZ')
  |> startProfileAt([-79.26, 95.04], %)
  |> line([112.54, 127.64], %, $seg02)
  |> line([170.36, -121.61], %, $seg01)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
const launderExtrudeThroughVar = extrude001
const sketch002 = startSketchOn(launderExtrudeThroughVar, seg02)
  |> startProfileAt([-100.54, 16.99], %)
  |> line([0, 20.03], %)
  |> line([62.61, 0], %, $seg03)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)      
`
      )
    }, KCL_DEFAULT_LENGTH)
    await page.setViewportSize({ width: 1000, height: 500 })
    await page.goto('/')
    await u.waitForAuthSkipAppStart()

    await u.openDebugPanel()
    await u.expectCmdLog('[data-message-type="execution-done"]', 10_000)
    await u.closeDebugPanel()

    await u.openAndClearDebugPanel()
    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_look_at',
        vantage: { x: 1139.49, y: -7053, z: 8597.31 },
        center: { x: -2206.68, y: -1298.36, z: 60 },
        up: { x: 0, y: 0, z: 1 },
      },
    })
    await page.waitForTimeout(100)
    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_get_settings',
      },
    })
    await page.waitForTimeout(100)

    // attempt delete
    await page.mouse.click(930, 139)
    await page.waitForTimeout(100)
    await expect(page.locator('.cm-activeLine')).toHaveText(
      '|> line([170.36, -121.61], %, $seg01)'
    )
    await u.clearCommandLogs()
    await page.keyboard.press('Backspace')

    await expect(page.getByText('Unable to delete part')).toBeVisible()
  })
  test('Hovering over 3d features highlights code', async ({ page }) => {
    const u = await getUtils(page)
    await page.addInitScript(async (KCL_DEFAULT_LENGTH) => {
      localStorage.setItem(
        'persistCode',
        `const part001 = startSketchOn('XZ')
    |> startProfileAt([20, 0], %)
    |> line([7.13, 4 + 0], %)
    |> angledLine({ angle: 3 + 0, length: 3.14 + 0 }, %)
    |> lineTo([20.14 + 0, -0.14 + 0], %)
    |> xLineTo(29 + 0, %)
    |> yLine(-3.14 + 0, %, $a)
    |> xLine(1.63, %)
    |> angledLineOfXLength({ angle: 3 + 0, length: 3.14 }, %)
    |> angledLineOfYLength({ angle: 30, length: 3 + 0 }, %)
    |> angledLineToX({ angle: 22.14 + 0, to: 12 }, %)
    |> angledLineToY({ angle: 30, to: 11.14 }, %)
    |> angledLineThatIntersects({
          angle: 3.14,
          intersectTag: a,
          offset: 0
        }, %)
    |> tangentialArcTo([13.14 + 0, 13.14], %)
    |> close(%)
    |> extrude(5 + 7, %)
  `
      )
    }, KCL_DEFAULT_LENGTH)
    await page.setViewportSize({ width: 1000, height: 500 })

    await u.waitForAuthSkipAppStart()

    // wait for execution done
    await u.openDebugPanel()
    await u.expectCmdLog('[data-message-type="execution-done"]')
    await u.closeDebugPanel()

    await u.openAndClearDebugPanel()
    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_look_at',
        vantage: { x: 0, y: -1250, z: 580 },
        center: { x: 0, y: 0, z: 0 },
        up: { x: 0, y: 0, z: 1 },
      },
    })
    await page.waitForTimeout(100)
    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_get_settings',
      },
    })
    await page.waitForTimeout(100)
    await u.closeDebugPanel()

    const extrusionTop: Coords2d = [800, 240]
    const flatExtrusionFace: Coords2d = [960, 160]
    const arc: Coords2d = [840, 160]
    const close: Coords2d = [720, 200]
    const nothing: Coords2d = [600, 200]

    await page.mouse.move(nothing[0], nothing[1])
    await page.mouse.click(nothing[0], nothing[1])

    await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
    await page.waitForTimeout(200)

    await page.mouse.move(extrusionTop[0], extrusionTop[1])
    await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
    await page.mouse.move(nothing[0], nothing[1])
    await expect(page.getByTestId('hover-highlight').first()).not.toBeVisible()

    await page.mouse.move(arc[0], arc[1])
    await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
    await page.mouse.move(nothing[0], nothing[1])
    await expect(page.getByTestId('hover-highlight').first()).not.toBeVisible()

    await page.mouse.move(close[0], close[1])
    await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
    await page.mouse.move(nothing[0], nothing[1])
    await expect(page.getByTestId('hover-highlight').first()).not.toBeVisible()

    await page.mouse.move(flatExtrusionFace[0], flatExtrusionFace[1])
    await expect(page.getByTestId('hover-highlight')).toHaveCount(6) // multiple lines
    await page.mouse.move(nothing[0], nothing[1])
    await page.waitForTimeout(100)
    await expect(page.getByTestId('hover-highlight').first()).not.toBeVisible()
  })
  test("Extrude button should be disabled if there's no extrudable geometry when nothing is selected", async ({
    page,
  }) => {
    const u = await getUtils(page)
    await page.addInitScript(async () => {
      localStorage.setItem(
        'persistCode',
        `const sketch001 = startSketchOn('XZ')
  |> startProfileAt([3.29, 7.86], %)
  |> line([2.48, 2.44], %)
  |> line([2.66, 1.17], %)
  |> line([3.75, 0.46], %)
  |> line([4.99, -0.46], %, $seg01)
  |> line([3.3, -2.12], %)
  |> line([2.16, -3.33], %)
  |> line([0.85, -3.08], %)
  |> line([-0.18, -3.36], %)
  |> line([-3.86, -2.73], %)
  |> line([-17.67, 0.85], %)
  |> close(%)
const extrude001 = extrude(10, sketch001)
  `
      )
    })
    await page.setViewportSize({ width: 1000, height: 500 })

    await u.waitForAuthSkipAppStart()

    // wait for execution done
    await u.openDebugPanel()
    await u.expectCmdLog('[data-message-type="execution-done"]')
    await u.closeDebugPanel()

    const selectUnExtrudable = () =>
      page.getByText(`line([4.99, -0.46], %, $seg01)`).click()
    const clickEmpty = () => page.mouse.click(700, 460)
    await selectUnExtrudable()
    // expect extrude button to be disabled
    await expect(page.getByRole('button', { name: 'Extrude' })).toBeDisabled()

    await clickEmpty()

    // expect active line to contain nothing
    await expect(page.locator('.cm-activeLine')).toHaveText('')
    // and extrude to still be disabled
    await expect(page.getByRole('button', { name: 'Extrude' })).toBeDisabled()

    const codeToAdd = `${await u.codeLocator.allInnerTexts()}
const sketch002 = startSketchOn(extrude001, $seg01)
  |> startProfileAt([-12.94, 6.6], %)
  |> line([2.45, -0.2], %)
  |> line([-2, -1.25], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
`
    await u.codeLocator.fill(codeToAdd)

    await selectUnExtrudable()
    // expect extrude button to be disabled
    await expect(page.getByRole('button', { name: 'Extrude' })).toBeDisabled()

    await clickEmpty()
    await expect(page.locator('.cm-activeLine')).toHaveText('')
    // there's not extrudable geometry, so button should be enabled
    await expect(
      page.getByRole('button', { name: 'Extrude' })
    ).not.toBeDisabled()
  })

  test('Fillet button states test', async ({ page }) => {
    const u = await getUtils(page)
    await page.addInitScript(async () => {
      localStorage.setItem(
        'persistCode',
        `const sketch001 = startSketchOn('XZ')
  |> startProfileAt([-5, -5], %)
  |> line([0, 10], %)
  |> line([10, 0], %)
  |> line([0, -10], %)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)`
      )
    })

    await page.setViewportSize({ width: 1000, height: 500 })
    await u.waitForAuthSkipAppStart()
    await u.openDebugPanel()
    await u.expectCmdLog('[data-message-type="execution-done"]')
    await u.closeDebugPanel()

    const selectSegment = () => page.getByText(`line([10, 0], %)`).click()
    const selectClose = () => page.getByText(`close(%)`).click()
    const clickEmpty = () => page.mouse.click(950, 100)

    // expect fillet button without any bodies in the scene
    await selectSegment()
    await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
    await clickEmpty()
    await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()

    // test fillet button with the body in the scene
    const codeToAdd = `${await u.codeLocator.allInnerTexts()}
const extrude001 = extrude(10, sketch001)`
    await u.codeLocator.fill(codeToAdd)
    await selectSegment()
    await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
    await selectClose()
    await expect(page.getByRole('button', { name: 'Fillet' })).toBeDisabled()
    await clickEmpty()
    await expect(page.getByRole('button', { name: 'Fillet' })).toBeEnabled()
  })

  const removeAfterFirstParenthesis = (inputString: string) => {
    const index = inputString.indexOf('(')
    if (index !== -1) {
      return inputString.substring(0, index)
    }
    return inputString // return the original string if '(' is not found
  }

  test('Testing selections (and hovers) work on sketches when NOT in sketch mode', async ({
    page,
  }) => {
    const cases = [
      {
        pos: [694, 185],
        expectedCode: 'line([74.36, 130.4], %, $seg01)',
      },
      {
        pos: [816, 244],
        expectedCode: 'angledLine([segAng(seg01), yo], %)',
      },
      {
        pos: [1107, 161],
        expectedCode: 'tangentialArcTo([167.95, -28.85], %)',
      },
    ] as const
    await page.addInitScript(
      async ({ cases }) => {
        localStorage.setItem(
          'persistCode',
          `const yo = 79
const part001 = startSketchOn('XZ')
  |> startProfileAt([-7.54, -26.74], %)
  |> ${cases[0].expectedCode}
  |> line([-3.19, -138.43], %)
  |> ${cases[1].expectedCode}
  |> line([41.19, 28.97 + 5], %)
  |> ${cases[2].expectedCode}`
        )
      },
      { cases }
    )
    const u = await getUtils(page)
    await page.setViewportSize({ width: 1200, height: 500 })

    await u.waitForAuthSkipAppStart()
    await u.openAndClearDebugPanel()

    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_look_at',
        vantage: { x: -449, y: -7503, z: 99 },
        center: { x: -449, y: 0, z: 99 },
        up: { x: 0, y: 0, z: 1 },
      },
    })
    await u.waitForCmdReceive('default_camera_look_at')
    await u.clearAndCloseDebugPanel()

    // end setup, now test hover and selects
    for (const { pos, expectedCode } of cases) {
      // hover over segment, check it's content
      await page.mouse.move(pos[0], pos[1], { steps: 5 })
      await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
      await expect(page.getByTestId('hover-highlight').first()).toHaveText(
        expectedCode
      )
      // hover over segment, click it and check the cursor has move to the right place
      await page.mouse.click(pos[0], pos[1])
      await expect(page.locator('.cm-activeLine')).toHaveText(
        '|> ' + expectedCode
      )
    }
  })
  test("Hovering and selection of extruded faces works, and is not overridden shortly after user's click", async ({
    page,
  }) => {
    await page.addInitScript(async () => {
      localStorage.setItem(
        'persistCode',
        `const sketch001 = startSketchOn('XZ')
  |> startProfileAt([-79.26, 95.04], %)
  |> line([112.54, 127.64], %)
  |> line([170.36, -121.61], %, $seg01)
  |> lineTo([profileStartX(%), profileStartY(%)], %)
  |> close(%)
const extrude001 = extrude(50, sketch001)
        `
      )
    })
    const u = await getUtils(page)
    await page.setViewportSize({ width: 1200, height: 500 })

    await u.waitForAuthSkipAppStart()
    await u.openAndClearDebugPanel()

    await u.sendCustomCmd({
      type: 'modeling_cmd_req',
      cmd_id: uuidv4(),
      cmd: {
        type: 'default_camera_look_at',
        vantage: { x: 6615, y: -9505, z: 10344 },
        center: { x: 1579, y: -635, z: 4035 },
        up: { x: 0, y: 0, z: 1 },
      },
    })
    await u.waitForCmdReceive('default_camera_look_at')
    await u.clearAndCloseDebugPanel()

    await page.waitForTimeout(1000)

    let noHoverColor: [number, number, number] = [82, 82, 82]
    let hoverColor: [number, number, number] = [116, 116, 116]
    let selectColor: [number, number, number] = [144, 148, 97]

    const extrudeWall = { x: 670, y: 275 }
    const extrudeText = `line([170.36, -121.61], %, $seg01)`

    const cap = { x: 594, y: 283 }
    const capText = `startProfileAt([-79.26, 95.04], %)`

    const nothing = { x: 946, y: 229 }

    await expect
      .poll(() => u.getGreatestPixDiff(extrudeWall, noHoverColor))
      .toBeLessThan(5)
    await page.mouse.move(nothing.x, nothing.y)
    await page.waitForTimeout(100)
    await page.mouse.move(extrudeWall.x, extrudeWall.y)
    await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
    await expect(page.getByTestId('hover-highlight').first()).toContainText(
      removeAfterFirstParenthesis(extrudeText)
    )
    await page.waitForTimeout(200)
    await expect(
      await u.getGreatestPixDiff(extrudeWall, hoverColor)
    ).toBeLessThan(6)
    await page.mouse.click(extrudeWall.x, extrudeWall.y)
    await expect(page.locator('.cm-activeLine')).toHaveText(`|> ${extrudeText}`)
    await page.waitForTimeout(200)
    await expect(
      await u.getGreatestPixDiff(extrudeWall, selectColor)
    ).toBeLessThan(6)
    await page.waitForTimeout(1000)
    // check color stays there, i.e. not overridden (this was a bug previously)
    await expect(
      await u.getGreatestPixDiff(extrudeWall, selectColor)
    ).toBeLessThan(6)

    await page.mouse.move(nothing.x, nothing.y)
    await page.waitForTimeout(300)
    await expect(page.getByTestId('hover-highlight')).not.toBeVisible()

    // because of shading, color is not exact everywhere on the face
    noHoverColor = [104, 104, 104]
    hoverColor = [134, 134, 134]
    selectColor = [158, 162, 110]

    await expect(await u.getGreatestPixDiff(cap, noHoverColor)).toBeLessThan(6)
    await page.mouse.move(cap.x, cap.y)
    await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
    await expect(page.getByTestId('hover-highlight').first()).toContainText(
      removeAfterFirstParenthesis(capText)
    )
    await page.waitForTimeout(200)
    await expect(await u.getGreatestPixDiff(cap, hoverColor)).toBeLessThan(6)
    await page.mouse.click(cap.x, cap.y)
    await expect(page.locator('.cm-activeLine')).toHaveText(`|> ${capText}`)
    await page.waitForTimeout(200)
    await expect(await u.getGreatestPixDiff(cap, selectColor)).toBeLessThan(6)
    await page.waitForTimeout(1000)
    // check color stays there, i.e. not overridden (this was a bug previously)
    await expect(await u.getGreatestPixDiff(cap, selectColor)).toBeLessThan(6)
  })
  test("Various pipe expressions should and shouldn't allow edit and or extrude", async ({
    page,
  }) => {
    const u = await getUtils(page)
    const selectionsSnippets = {
      extrudeAndEditBlocked: '|> startProfileAt([10.81, 32.99], %)',
      extrudeAndEditBlockedInFunction: '|> startProfileAt(pos, %)',
      extrudeAndEditAllowed: '|> startProfileAt([15.72, 4.7], %)',
      editOnly: '|> startProfileAt([15.79, -14.6], %)',
    }
    await page.addInitScript(
      async ({
        extrudeAndEditBlocked,
        extrudeAndEditBlockedInFunction,
        extrudeAndEditAllowed,
        editOnly,
      }: any) => {
        localStorage.setItem(
          'persistCode',
          `const part001 = startSketchOn('XZ')
    ${extrudeAndEditBlocked}
    |> line([25.96, 2.93], %)
    |> line([5.25, -5.72], %)
    |> line([-2.01, -10.35], %)
    |> line([-27.65, -2.78], %)
    |> close(%)
    |> extrude(5, %)
  const sketch002 = startSketchOn('XZ')
    ${extrudeAndEditAllowed}
    |> line([10.32, 6.47], %)
    |> line([9.71, -6.16], %)
    |> line([-3.08, -9.86], %)
    |> line([-12.02, -1.54], %)
    |> close(%)
  const sketch003 = startSketchOn('XZ')
    ${editOnly}
    |> line([27.55, -1.65], %)
    |> line([4.95, -8], %)
    |> line([-20.38, -10.12], %)
    |> line([-15.79, 17.08], %)
  
  fn yohey = (pos) => {
    const sketch004 = startSketchOn('XZ')
    ${extrudeAndEditBlockedInFunction}
    |> line([27.55, -1.65], %)
    |> line([4.95, -10.53], %)
    |> line([-20.38, -8], %)
    |> line([-15.79, 17.08], %)
    return ''
  }
  
      yohey([15.79, -34.6])
  `
        )
      },
      selectionsSnippets
    )
    await page.setViewportSize({ width: 1200, height: 1000 })

    await u.waitForAuthSkipAppStart()

    // wait for execution done
    await u.openDebugPanel()
    await u.expectCmdLog('[data-message-type="execution-done"]')
    await u.closeDebugPanel()

    // wait for start sketch as a proxy for the stream being ready
    await expect(
      page.getByRole('button', { name: 'Start Sketch' })
    ).not.toBeDisabled()

    await page.getByText(selectionsSnippets.extrudeAndEditBlocked).click()
    await expect(page.getByRole('button', { name: 'Extrude' })).toBeDisabled()

    await page.getByText(selectionsSnippets.extrudeAndEditAllowed).click()
    await expect(
      page.getByRole('button', { name: 'Extrude' })
    ).not.toBeDisabled()
    await expect(
      page.getByRole('button', { name: 'Edit Sketch' })
    ).not.toBeDisabled()

    await page.getByText(selectionsSnippets.editOnly).click()
    await expect(page.getByRole('button', { name: 'Extrude' })).toBeDisabled()
    await expect(
      page.getByRole('button', { name: 'Edit Sketch' })
    ).not.toBeDisabled()

    await page
      .getByText(selectionsSnippets.extrudeAndEditBlockedInFunction)
      .click()
    await expect(page.getByRole('button', { name: 'Extrude' })).toBeDisabled()
    await expect(
      page.getByRole('button', { name: 'Edit Sketch' })
    ).not.toBeVisible()
  })

  test('Deselecting line tool should mean nothing happens on click', async ({
    page,
  }) => {
    const u = await getUtils(page)
    await page.setViewportSize({ width: 1200, height: 500 })

    await u.waitForAuthSkipAppStart()
    await u.openDebugPanel()

    await expect(
      page.getByRole('button', { name: 'Start Sketch' })
    ).not.toBeDisabled()
    await expect(
      page.getByRole('button', { name: 'Start Sketch' })
    ).toBeVisible()

    // click on "Start Sketch" button
    await u.clearCommandLogs()
    await u.doAndWaitForImageDiff(
      () => page.getByRole('button', { name: 'Start Sketch' }).click(),
      200
    )

    await page.mouse.click(700, 200)

    await expect(page.locator('.cm-content')).toHaveText(
      `const sketch001 = startSketchOn('XZ')`
    )

    await page.waitForTimeout(600)

    let previousCodeContent = await page.locator('.cm-content').innerText()

    // deselect the line tool by clicking it
    await page.getByRole('button', { name: 'line Line', exact: true }).click()

    await page.mouse.click(700, 200)
    await page.waitForTimeout(100)
    await page.mouse.click(700, 250)
    await page.waitForTimeout(100)
    await page.mouse.click(750, 200)
    await page.waitForTimeout(100)

    // expect no change
    await expect(page.locator('.cm-content')).toHaveText(previousCodeContent)

    // select line tool again
    await page.getByRole('button', { name: 'line Line', exact: true }).click()

    await u.closeDebugPanel()

    // line tool should work as expected again
    await page.mouse.click(700, 200)
    await expect(page.locator('.cm-content')).not.toHaveText(
      previousCodeContent
    )
    previousCodeContent = await page.locator('.cm-content').innerText()

    await page.waitForTimeout(100)
    await page.mouse.click(700, 300)
    await expect(page.locator('.cm-content')).not.toHaveText(
      previousCodeContent
    )
    previousCodeContent = await page.locator('.cm-content').innerText()

    await page.waitForTimeout(100)
    await page.mouse.click(750, 300)
    await expect(page.locator('.cm-content')).not.toHaveText(
      previousCodeContent
    )
    previousCodeContent = await page.locator('.cm-content').innerText()
  })
})
