import { test, expect, type Page } from '@playwright/test'
import { execFileSync } from 'node:child_process'
import { existsSync } from 'node:fs'
import path from 'node:path'

type DashboardFixture = {
  email: string
  password: string
  username: string
}

const VITE_MANIFEST_PATH = path.join(process.cwd(), 'public', 'build', 'manifest.json')

function ensureCompiledAssets() {
  if (existsSync(VITE_MANIFEST_PATH)) {
    return
  }

  const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'

  execFileSync(npmCommand, ['run', 'build'], {
    cwd: process.cwd(),
    stdio: 'inherit',
  })
}

function seedDashboardFixture(): DashboardFixture {
  const token = `${Date.now().toString().slice(-6)}${Math.floor(Math.random() * 1000).toString().padStart(3, '0')}`
  const email = `e2e-dashboard-mobile-${token}@example.test`
  const username = `e2em${token}`.slice(0, 20)

  const script = [
    'use App\\Models\\User;',
    'use Illuminate\\Support\\Facades\\Hash;',
    `$user = User::updateOrCreate(['email' => '${email}'], [`,
    "  'name' => 'E2E Mobile Dashboard User',",
    `  'username' => '${username}',`,
    "  'onboarding_step' => 'complete',",
    "  'email_verified_at' => now(),",
    "  'is_active' => 1,",
    "  'password' => Hash::make('password'),",
    ']);',
    "echo json_encode(['email' => $user->email, 'password' => 'password', 'username' => $user->username]);",
  ].join(' ')

  const raw = execFileSync('php', ['artisan', 'tinker', `--execute=${script}`], {
    cwd: process.cwd(),
    encoding: 'utf8',
  })

  const lines = raw
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean)

  const jsonLine = [...lines].reverse().find((line) => line.startsWith('{') && line.endsWith('}'))
  if (!jsonLine) {
    throw new Error(`Unable to parse fixture JSON from tinker output: ${raw}`)
  }

  return JSON.parse(jsonLine) as DashboardFixture
}

function resetBotProtectionState() {
  const script = [
    'use Illuminate\\Support\\Facades\\DB;',
    'use Illuminate\\Support\\Facades\\Schema;',
    "foreach (['forum_bot_logs', 'forum_bot_ip_blacklist', 'forum_bot_device_fingerprints', 'forum_bot_behavior_profiles'] as $table) {",
    '  if (Schema::hasTable($table)) {',
    '    DB::table($table)->delete();',
    '  }',
    '}',
    "echo 'ok';",
  ].join(' ')

  execFileSync('php', ['artisan', 'tinker', `--execute=${script}`], {
    cwd: process.cwd(),
    encoding: 'utf8',
  })
}

async function login(page: Page, fixture: DashboardFixture) {
  for (let attempt = 0; attempt < 2; attempt += 1) {
    await page.goto('/login')
    const emailField = page.locator('input[name="email"]')
    const internalServerError = page.getByText('Internal Server Error')

    await Promise.race([
      emailField.waitFor({ state: 'visible', timeout: 8000 }),
      internalServerError.waitFor({ state: 'visible', timeout: 8000 }),
    ])

    if ((await internalServerError.isVisible().catch(() => false)) && !(await emailField.isVisible().catch(() => false))) {
      throw new Error('Dashboard mobile layout login failed because the login page returned an internal server error.')
    }

    await emailField.fill(fixture.email)
    await page.locator('input[name="password"]').fill(fixture.password)
    await page.getByRole('button', { name: 'Sign In' }).click()

    try {
      await page.waitForURL((url) => url.pathname !== '/login', { timeout: 8000, waitUntil: 'domcontentloaded' })
      await expect(page.getByRole('button', { name: /E2E Mobile Dashboard User/i })).toBeVisible()
      return
    } catch {
      const suspiciousActivity = page.getByText('Suspicious activity detected.')
      if (attempt === 0 && (await suspiciousActivity.isVisible().catch(() => false))) {
        resetBotProtectionState()
        continue
      }

      throw new Error('Dashboard mobile layout login failed before reaching an authenticated page.')
    }
  }
}

async function expectNoHorizontalOverflow(page: Page) {
  const dimensions = await page.evaluate(() => ({
    clientWidth: document.documentElement.clientWidth,
    scrollWidth: document.documentElement.scrollWidth,
  }))

  expect(
    dimensions.scrollWidth,
    `Expected no horizontal overflow, but scrollWidth=${dimensions.scrollWidth} and clientWidth=${dimensions.clientWidth}`
  ).toBeLessThanOrEqual(dimensions.clientWidth + 1)
}

test.describe('Dashboard mobile layout', () => {
  test.describe.configure({ mode: 'serial' })
  test.use({ viewport: { width: 390, height: 844 } })

  let fixture: DashboardFixture

  test.beforeAll(() => {
    ensureCompiledAssets()
    fixture = seedDashboardFixture()
  })

  test.beforeEach(() => {
    resetBotProtectionState()
  })

  test('dashboard home fits mobile width', async ({ page }) => {
    await login(page, fixture)
    await page.goto('/dashboard', { waitUntil: 'domcontentloaded' })
    await expect(page.getByRole('heading', { name: /welcome back/i })).toBeVisible()
    await page.waitForLoadState('networkidle')

    await expectNoHorizontalOverflow(page)
    await expect(page.getByRole('heading', { name: 'Your dashboard snapshot' })).toBeVisible()
  })

  test('followers page fits mobile width', async ({ page }) => {
    await login(page, fixture)
    await page.goto('/dashboard/followers', { waitUntil: 'domcontentloaded' })
    await expect(page.getByRole('heading', { name: 'People Following Me' })).toBeVisible()
    await page.waitForLoadState('networkidle')

    await expectNoHorizontalOverflow(page)
    await expect(page.getByRole('link', { name: /discover creators/i })).toBeVisible()
  })

  test('following page fits mobile width', async ({ page }) => {
    await login(page, fixture)
    await page.goto('/dashboard/following', { waitUntil: 'domcontentloaded' })
    await expect(page.getByRole('heading', { name: 'People I Follow' })).toBeVisible()
    await page.waitForLoadState('networkidle')

    await expectNoHorizontalOverflow(page)
    await expect(page.getByRole('link', { name: /my followers/i })).toBeVisible()
  })
})
