import { expect, test } from '@playwright/test';
import { Wallet } from 'ethers';
import { createWalletContext } from '../../setup/wallet-provider';
import { getStackConfig, validateStackHealthy } from '../../setup/stack';
import {
  createPersonaFeedback,
  addFeedbackStep,
  writePersonaFeedback,
  mintEth,
  buyKrk,
  resetChainState,
  type PersonaFeedback,
} from './helpers';
import { mkdirSync, readFileSync } from 'fs';
import { join } from 'path';

const KRK_ADDRESS = JSON.parse(readFileSync(join(process.cwd(), 'onchain', 'deployments-local.json'), 'utf-8')).contracts.Kraiken.toLowerCase();

const STACK_CONFIG = getStackConfig();
const STACK_RPC_URL = STACK_CONFIG.rpcUrl;
const STACK_WEBAPP_URL = STACK_CONFIG.webAppUrl;
const LANDING_PAGE_URL = 'http://localhost:8081/';

// Account for tests
const ACCOUNT_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
const ACCOUNT_ADDRESS = new Wallet(ACCOUNT_PRIVATE_KEY).address;

test.describe('Test A: Passive Holder Journey', () => {
  test.beforeAll(async () => {
    await resetChainState(STACK_RPC_URL);
    await validateStackHealthy(STACK_CONFIG);
  });

  test.describe.serial('Tyler - Retail Degen ("sell me in 30 seconds")', () => {
    let feedback: PersonaFeedback;

    test.beforeAll(() => {
      feedback = createPersonaFeedback('tyler', 'A', 'passive-holder');
    });

    test('Tyler evaluates landing page value prop', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      const observations: string[] = [];

      try {
        // Step 1: Navigate to landing page
        await page.goto(LANDING_PAGE_URL, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2_000);

        // Tyler's quick evaluation
        observations.push('Scanning page... do I see APY numbers? Big buttons? What\'s the hook?');

        // Check for value prop clarity
        const hasGetKrkButton = await page.getByRole('button', { name: /get.*krk/i }).isVisible().catch(() => false);
        if (hasGetKrkButton) {
          observations.push('✓ "Get KRK" button is visible and prominent - good CTA');
        } else {
          observations.push('✗ No clear "Get KRK" button visible - where do I start?');
        }

        // Check for stats/numbers that catch attention
        const hasStats = await page.locator('text=/\\d+%|\\$\\d+|APY/i').first().isVisible().catch(() => false);
        if (hasStats) {
          observations.push('✓ Numbers visible - I see stats, that\'s good for credibility');
        } else {
          observations.push('✗ No flashy APY or TVL numbers - nothing to grab my attention');
        }

        // Crypto jargon check
        const pageText = await page.textContent('body') || '';
        const jargonWords = ['harberger', 'vwap', 'tokenomics', 'liquidity', 'leverage'];
        const foundJargon = jargonWords.filter(word => pageText.toLowerCase().includes(word));
        if (foundJargon.length > 2) {
          observations.push(`⚠ Too much jargon: ${foundJargon.join(', ')} - might scare normies away`);
        } else {
          observations.push('✓ Copy is relatively clean, not too technical');
        }

        // Protocol Health section
        const hasProtocolHealth = await page.getByText(/protocol health|system status/i).isVisible().catch(() => false);
        if (hasProtocolHealth) {
          observations.push('✓ Protocol Health section builds trust - shows transparency');
        } else {
          observations.push('Missing: No visible protocol health/stats - how do I know this isn\'t rugpull?');
        }

        // Screenshot
        const screenshotDir = join('test-results', 'usertest', 'tyler-a');
        mkdirSync(screenshotDir, { recursive: true });
        const screenshotPath = join(screenshotDir, `landing-page-${Date.now()}.png`);
        await page.screenshot({ path: screenshotPath, fullPage: true });

        addFeedbackStep(feedback, 'landing-page', observations, screenshotPath);
        
        // Tyler's 30-second verdict
        const verdict = hasGetKrkButton && hasStats ? 
          'PASS: Clear CTA, visible stats. I\'d click through to learn more.' :
          'FAIL: Not sold in 30 seconds. Needs bigger numbers and clearer value prop.';
        observations.push(`Tyler\'s verdict: ${verdict}`);

      } finally {
        await context.close();
      }
    });

    test('Tyler clicks Get KRK and checks Uniswap link', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      const observations: string[] = [];

      try {
        await page.goto(LANDING_PAGE_URL, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(1_000);

        // Click Get KRK button
        const getKrkButton = page.getByRole('button', { name: /get.*krk/i }).first();
        const buttonVisible = await getKrkButton.isVisible({ timeout: 5_000 }).catch(() => false);
        
        if (buttonVisible) {
          await getKrkButton.click();
          // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
          await page.waitForTimeout(2_000);

          // Check if navigated to web-app
          const currentUrl = page.url();
          if (currentUrl.includes('get-krk') || currentUrl.includes('5173')) {
            observations.push('✓ Get KRK button navigated to web-app');
          } else {
            observations.push(`✗ Get KRK button went to wrong place: ${currentUrl}`);
          }

          // Check for Uniswap link with correct token address

          const uniswapLink = await page.locator(`a[href*="uniswap"][href*="${KRK_ADDRESS}"]`).isVisible().catch(() => false);
          if (uniswapLink) {
            observations.push('✓ Uniswap link exists with correct KRK token address');
          } else {
            const anyUniswapLink = await page.locator('a[href*="uniswap"]').isVisible().catch(() => false);
            if (anyUniswapLink) {
              observations.push('⚠ Uniswap link exists but may have wrong token address');
            } else {
              observations.push('✗ No Uniswap link found - how do I actually get KRK?');
            }
          }

          // Screenshot
          const screenshotDir = join('test-results', 'usertest', 'tyler-a');
          const screenshotPath = join(screenshotDir, `get-krk-page-${Date.now()}.png`);
          await page.screenshot({ path: screenshotPath, fullPage: true });

          addFeedbackStep(feedback, 'get-krk', observations, screenshotPath);

        } else {
          observations.push('✗ CRITICAL: Get KRK button not found on landing page');
          addFeedbackStep(feedback, 'get-krk', observations);
        }

      } finally {
        await context.close();
      }
    });

    test('Tyler simulates having KRK and checks return value', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      const observations: string[] = [];

      try {
        // Navigate to web-app to connect wallet
        await page.goto(`${STACK_WEBAPP_URL}/app/`, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2_000);

        // Mint ETH and buy KRK programmatically
        observations.push('Buying KRK via on-chain swap...');
        await mintEth(page, STACK_RPC_URL, ACCOUNT_ADDRESS, '10');
        
        try {
          await buyKrk(page, '1', STACK_RPC_URL, ACCOUNT_PRIVATE_KEY);
          observations.push('✓ Successfully acquired KRK via swap');
        } catch (error: any) {
          observations.push(`✗ KRK purchase failed: ${error.message}`);
          feedback.overall.friction.push('Cannot acquire KRK through documented flow');
        }

        // Navigate back to landing page
        await page.goto(LANDING_PAGE_URL, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2_000);

        // Check for reasons to return
        observations.push('Now I have KRK... why would I come back to landing page?');

        const hasStatsSection = await page.getByText(/stats|protocol health|dashboard/i).isVisible().catch(() => false);
        const hasPriceInfo = await page.locator('text=/price|\\$[0-9]/i').isVisible().catch(() => false);
        const hasAPY = await page.locator('text=/APY|%/i').isVisible().catch(() => false);

        if (hasStatsSection || hasPriceInfo || hasAPY) {
          observations.push('✓ Landing page has stats/info - gives me reason to check back');
        } else {
          observations.push('✗ No compelling reason to return to landing page - just a static ad');
          feedback.overall.friction.push('Landing page offers no ongoing value for holders');
        }

        // Screenshot
        const screenshotDir = join('test-results', 'usertest', 'tyler-a');
        const screenshotPath = join(screenshotDir, `return-check-${Date.now()}.png`);
        await page.screenshot({ path: screenshotPath, fullPage: true });

        addFeedbackStep(feedback, 'return-value', observations, screenshotPath);

        // Tyler's overall assessment
        const wouldReturn = hasStatsSection || hasPriceInfo || hasAPY;
        feedback.overall.wouldBuy = observations.some(o => o.includes('✓ Successfully acquired KRK'));
        feedback.overall.wouldReturn = wouldReturn;

        if (!wouldReturn) {
          feedback.overall.friction.push('Landing page is one-time conversion, no repeat visit value');
        }

      } finally {
        await context.close();
        writePersonaFeedback(feedback);
      }
    });
  });

  test.describe.serial('Alex - Newcomer ("what even is this?")', () => {
    let feedback: PersonaFeedback;

    test.beforeAll(() => {
      feedback = createPersonaFeedback('alex', 'A', 'passive-holder');
    });

    test('Alex tries to understand the landing page', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      const observations: string[] = [];

      try {
        await page.goto(LANDING_PAGE_URL, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2_000);

        observations.push('Reading the page... trying to understand what this protocol does');

        // Check for explanatory content
        const hasExplainer = await page.getByText(/how it works|what is|getting started/i).isVisible().catch(() => false);
        if (hasExplainer) {
          observations.push('✓ Found "How it works" or explainer section - helpful!');
        } else {
          observations.push('✗ No clear explainer - I\'m lost and don\'t know what this is');
          feedback.overall.friction.push('No beginner-friendly explanation on landing page');
        }

        // Jargon overload check
        const pageText = await page.textContent('body') || '';
        const complexTerms = ['harberger', 'vwap', 'amm', 'liquidity pool', 'tokenomics', 'leverage', 'tax rate'];
        const foundTerms = complexTerms.filter(term => pageText.toLowerCase().includes(term));
        
        if (foundTerms.length > 3) {
          observations.push(`⚠ Jargon overload (${foundTerms.length} complex terms): ${foundTerms.join(', ')}`);
          observations.push('As a newcomer, this is intimidating and confusing');
          feedback.overall.friction.push('Too much unexplained crypto jargon');
        } else {
          observations.push('✓ Language is relatively accessible');
        }

        // Check for Get KRK button clarity
        const getKrkButton = await page.getByRole('button', { name: /get.*krk/i }).isVisible().catch(() => false);
        if (getKrkButton) {
          observations.push('✓ "Get KRK" button is clear - I understand that\'s the next step');
        } else {
          observations.push('✗ Not sure how to start or what to do first');
        }

        // Trust signals
        const hasTrustSignals = await page.getByText(/audit|secure|safe|verified/i).isVisible().catch(() => false);
        if (hasTrustSignals) {
          observations.push('✓ Trust signals present (audit/secure) - makes me feel safer');
        } else {
          observations.push('⚠ No visible security/audit info - how do I know this is safe?');
          feedback.overall.friction.push('Lack of trust signals for newcomers');
        }

        // Screenshot
        const screenshotDir = join('test-results', 'usertest', 'alex-a');
        mkdirSync(screenshotDir, { recursive: true });
        const screenshotPath = join(screenshotDir, `landing-confusion-${Date.now()}.png`);
        await page.screenshot({ path: screenshotPath, fullPage: true });

        addFeedbackStep(feedback, 'landing-page', observations, screenshotPath);

      } finally {
        await context.close();
      }
    });

    test('Alex explores Get KRK page and looks for guidance', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      const observations: string[] = [];

      try {
        await page.goto(LANDING_PAGE_URL, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(1_000);

        // Try to click Get KRK
        const getKrkButton = page.getByRole('button', { name: /get.*krk/i }).first();
        const buttonVisible = await getKrkButton.isVisible({ timeout: 5_000 }).catch(() => false);

        if (buttonVisible) {
          await getKrkButton.click();
          // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
          await page.waitForTimeout(2_000);

          observations.push('Clicked "Get KRK" - now what?');

          // Look for step-by-step instructions
          const hasInstructions = await page.getByText(/step|how to|tutorial|guide/i).isVisible().catch(() => false);
          if (hasInstructions) {
            observations.push('✓ Found step-by-step instructions - very helpful for newcomer');
          } else {
            observations.push('✗ No clear instructions on how to proceed');
            feedback.overall.friction.push('Get KRK page lacks step-by-step guide');
          }

          // Check for Uniswap link explanation
          const uniswapLink = await page.locator('a[href*="uniswap"]').first().isVisible().catch(() => false);
          if (uniswapLink) {
            // Check if there's explanatory text near the link
            const hasContext = await page.getByText(/swap|exchange|buy on uniswap/i).isVisible().catch(() => false);
            if (hasContext) {
              observations.push('✓ Uniswap link has context/explanation');
            } else {
              observations.push('⚠ Uniswap link present but no explanation - what is Uniswap?');
              feedback.overall.friction.push('No explanation of external links (Uniswap)');
            }
          } else {
            observations.push('✗ No Uniswap link found - how do I get KRK?');
          }

          // Screenshot
          const screenshotDir = join('test-results', 'usertest', 'alex-a');
          const screenshotPath = join(screenshotDir, `get-krk-page-${Date.now()}.png`);
          await page.screenshot({ path: screenshotPath, fullPage: true });

          addFeedbackStep(feedback, 'get-krk', observations, screenshotPath);

        } else {
          observations.push('✗ Could not find Get KRK button');
          addFeedbackStep(feedback, 'get-krk', observations);
        }

      } finally {
        await context.close();
      }
    });

    test('Alex simulates getting KRK and evaluates next steps', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      const observations: string[] = [];

      try {
        await page.goto(`${STACK_WEBAPP_URL}/app/`, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2_000);

        // Simulate getting KRK
        observations.push('Pretending I figured out Uniswap and bought KRK...');
        await mintEth(page, STACK_RPC_URL, ACCOUNT_ADDRESS, '10');
        
        try {
          await buyKrk(page, '1', STACK_RPC_URL, ACCOUNT_PRIVATE_KEY);
          observations.push('✓ Somehow managed to get KRK');
        } catch (error: any) {
          observations.push(`✗ Failed to get KRK: ${error.message}`);
        }

        // Navigate back to landing
        await page.goto(LANDING_PAGE_URL, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2_000);

        observations.push('Okay, I have KRK now... what should I do with it?');

        // Look for holder guidance
        const hasHolderInfo = await page.getByText(/hold|stake|earn|now what/i).isVisible().catch(() => false);
        if (hasHolderInfo) {
          observations.push('✓ Found guidance for what to do after getting KRK');
        } else {
          observations.push('✗ No clear next steps - just have tokens sitting in wallet');
          feedback.overall.friction.push('No guidance for new holders on what to do next');
        }

        // Check for ongoing value
        const hasReasonToReturn = await page.getByText(/dashboard|stats|price|track/i).isVisible().catch(() => false);
        if (hasReasonToReturn) {
          observations.push('✓ Landing page has info worth checking regularly');
        } else {
          observations.push('✗ No reason to come back to landing page');
        }

        // Screenshot
        const screenshotDir = join('test-results', 'usertest', 'alex-a');
        const screenshotPath = join(screenshotDir, `after-purchase-${Date.now()}.png`);
        await page.screenshot({ path: screenshotPath, fullPage: true });

        addFeedbackStep(feedback, 'post-purchase', observations, screenshotPath);

        // Alex's verdict
        const understandsValueProp = observations.some(o => o.includes('✓ Found "How it works"'));
        const knowsNextSteps = hasHolderInfo;

        feedback.overall.wouldBuy = understandsValueProp && observations.some(o => o.includes('✓ Somehow managed to get KRK'));
        feedback.overall.wouldReturn = hasReasonToReturn;

        if (!understandsValueProp) {
          feedback.overall.friction.push('Value proposition unclear to crypto newcomers');
        }
        if (!knowsNextSteps) {
          feedback.overall.friction.push('Post-purchase journey undefined');
        }

      } finally {
        await context.close();
        writePersonaFeedback(feedback);
      }
    });
  });

  test.describe.serial('Sarah - Yield Farmer ("is this worth my time?")', () => {
    let feedback: PersonaFeedback;

    test.beforeAll(() => {
      feedback = createPersonaFeedback('sarah', 'A', 'passive-holder');
    });

    test('Sarah analyzes landing page metrics and credibility', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      const observations: string[] = [];

      try {
        await page.goto(LANDING_PAGE_URL, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2_000);

        observations.push('Scanning for key metrics: APY, TVL, risk factors...');

        // Check for APY/yield info
        const hasAPY = await page.locator('text=/\\d+%|APY|yield/i').isVisible().catch(() => false);
        if (hasAPY) {
          observations.push('✓ APY or yield percentage visible - good, I can compare to other protocols');
        } else {
          observations.push('✗ No clear APY shown - can\'t evaluate if this is competitive');
          feedback.overall.friction.push('No yield/APY displayed on landing page');
        }

        // Check for TVL
        const hasTVL = await page.locator('text=/TVL|total value locked|\\$[0-9]+[kmb]/i').isVisible().catch(() => false);
        if (hasTVL) {
          observations.push('✓ TVL visible - helps me assess protocol size and safety');
        } else {
          observations.push('⚠ No TVL shown - harder to gauge protocol maturity');
        }

        // Protocol Health section
        const hasProtocolHealth = await page.getByText(/protocol health|health|status/i).isVisible().catch(() => false);
        if (hasProtocolHealth) {
          observations.push('✓ Protocol Health section present - shows transparency and confidence');
        } else {
          observations.push('⚠ No protocol health metrics - how do I assess risk?');
          feedback.overall.friction.push('Missing protocol health/risk indicators');
        }

        // Audit info
        const hasAudit = await page.getByText(/audit|audited|security/i).isVisible().catch(() => false);
        if (hasAudit) {
          observations.push('✓ Audit information visible - critical for serious yield farmers');
        } else {
          observations.push('✗ No audit badge or security info - major red flag');
          feedback.overall.friction.push('No visible audit/security credentials');
        }

        // Smart contract addresses
        const hasContracts = await page.locator('text=/0x[a-fA-F0-9]{40}|contract address/i').isVisible().catch(() => false);
        if (hasContracts) {
          observations.push('✓ Contract addresses visible - I can verify on Etherscan');
        } else {
          observations.push('⚠ No contract addresses - want to verify before committing capital');
        }

        // Screenshot
        const screenshotDir = join('test-results', 'usertest', 'sarah-a');
        mkdirSync(screenshotDir, { recursive: true });
        const screenshotPath = join(screenshotDir, `landing-metrics-${Date.now()}.png`);
        await page.screenshot({ path: screenshotPath, fullPage: true });

        addFeedbackStep(feedback, 'landing-page', observations, screenshotPath);

      } finally {
        await context.close();
      }
    });

    test('Sarah evaluates Get KRK flow efficiency', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      const observations: string[] = [];

      try {
        await page.goto(LANDING_PAGE_URL, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(1_000);

        const getKrkButton = page.getByRole('button', { name: /get.*krk/i }).first();
        const buttonVisible = await getKrkButton.isVisible({ timeout: 5_000 }).catch(() => false);

        if (buttonVisible) {
          await getKrkButton.click();
          // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
          await page.waitForTimeout(2_000);

          observations.push('Evaluating acquisition flow - time is money');

          // Check for direct swap vs external redirect
          const currentUrl = page.url();
          const hasDirectSwap = await page.locator('input[placeholder*="amount" i]').isVisible({ timeout: 3_000 }).catch(() => false);
          
          if (hasDirectSwap) {
            observations.push('✓ Direct swap interface - efficient, no external redirects');
          } else {
            observations.push('⚠ Redirects to external swap - adds friction and gas costs');
          }

          // Uniswap link check
          const uniswapLink = await page.locator(`a[href*="uniswap"][href*="${KRK_ADDRESS}"]`).isVisible().catch(() => false);
          
          if (uniswapLink) {
            observations.push('✓ Uniswap link with correct token address - can verify liquidity');
          } else {
            observations.push('✗ No Uniswap link or wrong address - can\'t verify DEX liquidity');
            feedback.overall.friction.push('Cannot verify DEX liquidity before buying');
          }

          // Price impact warning
          const hasPriceImpact = await page.getByText(/price impact|slippage/i).isVisible().catch(() => false);
          if (hasPriceImpact) {
            observations.push('✓ Price impact/slippage shown - good UX for larger trades');
          } else {
            observations.push('⚠ No price impact warning - could be surprised by slippage');
          }

          // Screenshot
          const screenshotDir = join('test-results', 'usertest', 'sarah-a');
          const screenshotPath = join(screenshotDir, `get-krk-flow-${Date.now()}.png`);
          await page.screenshot({ path: screenshotPath, fullPage: true });

          addFeedbackStep(feedback, 'get-krk', observations, screenshotPath);

        } else {
          observations.push('✗ Get KRK button not found');
          addFeedbackStep(feedback, 'get-krk', observations);
        }

      } finally {
        await context.close();
      }
    });

    test('Sarah checks for holder value and monitoring tools', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      const observations: string[] = [];

      try {
        await page.goto(`${STACK_WEBAPP_URL}/app/`, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2_000);

        // Acquire KRK
        observations.push('Acquiring KRK to evaluate holder experience...');
        await mintEth(page, STACK_RPC_URL, ACCOUNT_ADDRESS, '10');
        
        try {
          await buyKrk(page, '2', STACK_RPC_URL, ACCOUNT_PRIVATE_KEY);
          observations.push('✓ KRK acquired');
        } catch (error: any) {
          observations.push(`✗ Acquisition failed: ${error.message}`);
          feedback.overall.friction.push('Programmatic acquisition flow broken');
        }

        // Return to landing page
        await page.goto(LANDING_PAGE_URL, { waitUntil: 'domcontentloaded' });
        // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for animation settling, wallet connector UI transitions, and debounced state updates in user-simulation tests. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2_000);

        observations.push('Now holding KRK - what ongoing value does landing page provide?');

        // Real-time stats
        const hasRealtimeStats = await page.locator('text=/live|24h|volume|price/i').isVisible().catch(() => false);
        if (hasRealtimeStats) {
          observations.push('✓ Real-time stats visible - makes landing page a monitoring dashboard');
        } else {
          observations.push('✗ No real-time data - no reason to return to landing page');
          feedback.overall.friction.push('Landing page provides no ongoing value for holders');
        }

        // Protocol health tracking
        const hasHealthMetrics = await page.getByText(/protocol health|system status|health score/i).isVisible().catch(() => false);
        if (hasHealthMetrics) {
          observations.push('✓ Protocol health tracking - helps me monitor risk');
        } else {
          observations.push('⚠ No protocol health dashboard - can\'t monitor protocol risk');
        }

        // Links to analytics
        const hasAnalytics = await page.locator('a[href*="dune"][href*="dexscreener"]').or(page.getByText(/analytics|charts/i)).isVisible().catch(() => false);
        if (hasAnalytics) {
          observations.push('✓ Links to analytics platforms - good for research');
        } else {
          observations.push('⚠ No links to Dune/DexScreener - harder to do deep analysis');
        }

        // Screenshot
        const screenshotDir = join('test-results', 'usertest', 'sarah-a');
        const screenshotPath = join(screenshotDir, `holder-dashboard-${Date.now()}.png`);
        await page.screenshot({ path: screenshotPath, fullPage: true });

        addFeedbackStep(feedback, 'holder-experience', observations, screenshotPath);

        // Sarah's ROI assessment
        const hasCompetitiveAPY = observations.some(o => o.includes('✓ APY or yield percentage visible'));
        const hasMonitoringTools = hasRealtimeStats || hasHealthMetrics;
        const lowFriction = feedback.overall.friction.length < 3;

        feedback.overall.wouldBuy = hasCompetitiveAPY && lowFriction;
        feedback.overall.wouldReturn = hasMonitoringTools;

        if (!hasMonitoringTools) {
          feedback.overall.friction.push('Insufficient monitoring/analytics tools for active yield farmers');
        }

        observations.push(`Sarah's verdict: ${feedback.overall.wouldBuy ? 'Worth allocating capital' : 'Not competitive enough'}`);
        observations.push(`Would return: ${feedback.overall.wouldReturn ? 'Yes, for monitoring' : 'No, one-time interaction only'}`);

      } finally {
        await context.close();
        writePersonaFeedback(feedback);
      }
    });
  });
});
