/**
 * Feature Documentation: Merge PR Button Fix
 *
 * Documents the "Merge PR to main" action button appearing correctly when
 * all conditions are met: clean working tree, open PR, checks passed,
 * write access, and merge allowed. A missing useMemo dependency on
 * checksStatus was causing the button to disappear; this fix adds it.
 *
 * Run with: pnpm test:feature-docs merge-pr-button-fix
 */
import { test, expect, resetApp } from '../_shared/electron-fixture'
import type { Page, ElectronApplication } from '@playwright/test'
import path from 'path'
import fs from 'fs'
import { fileURLToPath } from 'url'
import { screenshotElement } from '../_shared/screenshot-helpers'
import { generateFeaturePage, generateIndex, FeatureStep } from '../_shared/template'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

const FEATURE_DIR = __dirname
const SCREENSHOTS = path.join(FEATURE_DIR, 'screenshots')
const FEATURES_ROOT = path.join(__dirname, '..')

let page: Page
let electronApp: ElectronApplication
const steps: FeatureStep[] = []

/** Navigate the explorer panel to the source-control tab */
async function openSourceControl() {
  const explorerButton = page.locator('[data-panel-id="explorer-toggle"], [title*="Explorer"]').first()
  if (await explorerButton.isVisible()) {
    const cls = await explorerButton.getAttribute('class').catch(() => '')
    if (!cls?.includes('bg-accent')) {
      await explorerButton.click()
      await expect(page.locator('[data-panel-id="explorer"]')).toBeVisible()
    }
  }

  await page.evaluate(() => {
    const store = (window as Record<string, unknown>).__sessionStore as {
      getState: () => { activeSessionId: string; setExplorerFilter: (id: string, filter: string) => void }
    }
    if (!store) return
    const state = store.getState()
    state.setExplorerFilter(state.activeSessionId, 'source-control')
  })
  await expect(page.locator('[data-panel-id="explorer"]')).toBeVisible()
}

/** Switch to a session by ID */
async function switchToSession(sessionId: string) {
  await page.evaluate((id) => {
    const store = (window as Record<string, unknown>).__sessionStore as {
      getState: () => { sessions: { id: string }[]; setActiveSession: (id: string) => void }
    }
    if (!store) return
    const state = store.getState()
    const session = state.sessions.find((s: { id: string }) => s.id === id)
    if (session) state.setActiveSession(session.id)
  }, sessionId)
  // Wait for terminal to appear after session switch
  await page.locator('.xterm-screen').first().waitFor({ state: 'visible' })
}

test.beforeAll(async () => {
  await fs.promises.mkdir(SCREENSHOTS, { recursive: true })
  ;({ page, electronApp } = await resetApp())
})

test.afterAll(async () => {
  // Reset git clean override for subsequent tests
  await electronApp.evaluate((_electron) => {
    process.env.E2E_MOCK_GIT_CLEAN = ''
  })

  await generateFeaturePage(
    {
      title: 'Fix: Merge PR Button Visibility',
      description:
        'The "Merge PR to main" action button was disappearing from the source control ' +
        'panel due to a missing checksStatus dependency in the useMemo that computes ' +
        'condition state. When checksStatus changed, the memoized condition state was not ' +
        'recalculated, causing the checks-passed condition to become stale. This fix adds ' +
        'data.checksStatus to the dependency array so the button appears reliably.',
      steps,
    },
    FEATURE_DIR,
  )
  await generateIndex(FEATURES_ROOT)
})

test.describe.serial('Feature: Merge PR Button Fix', () => {
  test('Step 1: Feature branch with dirty working tree — merge button hidden', async () => {
    // Session 2 (backend-api) is on feature/auth with an open PR in E2E mock data
    await switchToSession('2')
    await openSourceControl()
    // Wait for source control panel to fully render
    await page.locator('[data-panel-id="explorer"]').waitFor({ state: 'visible' })

    // With uncommitted changes, Merge PR should NOT be visible
    const mergePrButton = page.locator('button:has-text("Merge PR to main")')
    await expect(mergePrButton).not.toBeVisible()

    // Commit with AI should be visible (has-changes condition met)
    const commitButton = page.locator('button:has-text("Commit with AI")')
    await expect(commitButton).toBeVisible()

    const explorer = page.locator('[data-panel-id="explorer"]')
    await screenshotElement(page, explorer, path.join(SCREENSHOTS, '01-dirty-no-merge.png'), {
      maxHeight: 600,
    })
    steps.push({
      screenshotPath: 'screenshots/01-dirty-no-merge.png',
      caption: 'Merge PR button hidden when working tree is dirty',
      description:
        'The feature/auth branch has an open PR (shown in the banner), but the working tree ' +
        'has uncommitted changes. The "clean" showWhen condition is false, so the "Merge PR ' +
        'to main" button is correctly hidden. "Commit with AI" appears instead.',
    })
  })

  test('Step 2: Clean working tree with open PR — merge button appears', async () => {
    // Set E2E_MOCK_GIT_CLEAN on the main process so git:status returns clean data.
    // This simulates the user having committed all changes.
    await electronApp.evaluate((_electron) => {
      process.env.E2E_MOCK_GIT_CLEAN = 'true'
    })

    // Wait for git polling (every 2s) to pick up the clean status, compute
    // branchStatus='open' from lastKnownPrState='OPEN', and for React to re-render
    const mergePrButton = page.locator('button:has-text("Merge PR to main")')
    await expect(mergePrButton).toBeVisible({ timeout: 10000 })

    // Commit with AI should be hidden (no changes)
    const commitButton = page.locator('button:has-text("Commit with AI")')
    await expect(commitButton).not.toBeVisible()

    const explorer = page.locator('[data-panel-id="explorer"]')
    await screenshotElement(page, explorer, path.join(SCREENSHOTS, '02-clean-merge-visible.png'), {
      maxHeight: 600,
    })
    steps.push({
      screenshotPath: 'screenshots/02-clean-merge-visible.png',
      caption: 'Merge PR button appears with clean tree and open PR',
      description:
        'After committing all changes, the working tree is clean. All six showWhen conditions ' +
        'for the merge button are now met: clean (no uncommitted files), open (PR is OPEN), ' +
        'checks-passed (CI checks passed), has-write-access (user can push), ' +
        'allow-approve-and-merge (repo setting enabled), and !review (not in review tab). ' +
        'With the fix, checksStatus changes are properly tracked so this button stays visible.',
    })
  })

  test('Step 3: Merge PR button close-up', async () => {
    const mergePrButton = page.locator('button:has-text("Merge PR to main")')
    await expect(mergePrButton).toBeVisible()

    await screenshotElement(page, mergePrButton, path.join(SCREENSHOTS, '03-merge-button-closeup.png'), {
      padding: 12,
    })
    steps.push({
      screenshotPath: 'screenshots/03-merge-button-closeup.png',
      caption: 'The "Merge PR to main" action button',
      description:
        'Close-up of the merge button. When clicked, it sends a prompt to the AI agent ' +
        'that pulls latest from main, resolves conflicts, runs validation, pushes, and ' +
        'merges the PR via `gh pr merge --merge`. The button only appears when all conditions ' +
        'are satisfied, preventing accidental merges.',
    })
  })

  test('Step 4: Main branch — no merge button (correct behavior)', async () => {
    // Switch to session 1 (on main branch) — merge button should not appear
    // even with clean git status, because there's no open PR on main
    await switchToSession('1')
    await openSourceControl()
    // Wait for source control panel to fully render
    await page.locator('[data-panel-id="explorer"]').waitFor({ state: 'visible' })

    const mergePrButton = page.locator('button:has-text("Merge PR to main")')
    await expect(mergePrButton).not.toBeVisible()

    const explorer = page.locator('[data-panel-id="explorer"]')
    await screenshotElement(page, explorer, path.join(SCREENSHOTS, '04-main-no-merge.png'), {
      maxHeight: 500,
    })
    steps.push({
      screenshotPath: 'screenshots/04-main-no-merge.png',
      caption: 'No merge button on main branch',
      description:
        'On the main branch there is no open PR, so the "open" condition is false and the ' +
        'merge button does not appear. The condition system correctly shows only relevant ' +
        'actions for each branch state.',
    })
  })
})
