import { test } from '@playwright/test';
import { Wallet } from 'ethers';
import { createWalletContext } from '../../setup/wallet-provider';
import { getStackConfig, validateStackHealthy } from '../../setup/stack';
import {
  createReport,
  connectWallet,
  mintEth,
  buyKrk,
  takeScreenshot,
  logObservation,
  recordAction,
  writeReport,
  attemptStake,
  resetChainState,
} from './helpers';

const STACK_CONFIG = getStackConfig();
const STACK_RPC_URL = STACK_CONFIG.rpcUrl;
const STACK_WEBAPP_URL = STACK_CONFIG.webAppUrl;

// Persona accounts (Anvil #1-5)
// Note: Pool has limited liquidity - 0.05 ETH buy yields ~3.99 KRK
// Staking 3 KRK leaves enough for upfront tax payment
const PERSONAS = [
  {
    name: 'Marcus Flash Chen',
    shortName: 'Marcus',
    privateKey: '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d',
    ethToMint: '10',
    ethToSpend: '0.05',
    stakeAmount: '3', // Conservative amount that fits within ~3.99 KRK balance
    taxRate: '2',
  },
  {
    name: 'Sarah Park',
    shortName: 'Sarah',
    privateKey: '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a',
    ethToMint: '10',
    ethToSpend: '0.05',
    stakeAmount: '3',
    taxRate: '2',
  },
  {
    name: 'Tyler Brooks',
    shortName: 'Tyler',
    privateKey: '0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6',
    ethToMint: '10',
    ethToSpend: '0.05',
    stakeAmount: '3',
    taxRate: '2',
  },
  {
    name: 'Priya Sharma',
    shortName: 'Priya',
    privateKey: '0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a',
    ethToMint: '10',
    ethToSpend: '0.05',
    stakeAmount: '3',
    taxRate: '2',
  },
  {
    name: 'Alex Rivera',
    shortName: 'Alex',
    privateKey: '0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba',
    ethToMint: '10',
    ethToSpend: '0.05',
    stakeAmount: '3',
    taxRate: '2',
  },
];

test.describe('All Personas - Fresh Pool State', () => {
  for (const persona of PERSONAS) {
    test(`${persona.name} completes full journey`, async ({ browser }) => {
      // Reset chain state before THIS persona
      // First call takes initial snapshot, subsequent calls revert to it
      console.log(`\n[ORCHESTRATOR] Resetting chain state for ${persona.name}...`);
      await resetChainState(STACK_RPC_URL);
      
      // Validate stack health once at start
      if (persona === PERSONAS[0]) {
        console.log('[ORCHESTRATOR] Validating stack health...');
        await validateStackHealthy(STACK_CONFIG);
      }

      const report = createReport(persona.name);
      const address = new Wallet(persona.privateKey).address.toLowerCase();

      console.log(`[${persona.shortName}] Starting test - fresh pool state`);

      const context = await createWalletContext(browser, {
        privateKey: persona.privateKey,
        rpcUrl: STACK_RPC_URL,
      });

      const page = await context.newPage();
      page.on('console', msg => console.log(`[BROWSER] ${msg.type()}: ${msg.text()}`));
      page.on('pageerror', error => console.log(`[BROWSER ERROR] ${error.message}`));

      try {
        // 1. Navigate to app
        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);
        await takeScreenshot(page, persona.shortName, '1-landing', report);
        logObservation(persona.shortName, 'Arrived at app', report);

        // 2. Connect wallet
        await connectWallet(page);
        await takeScreenshot(page, persona.shortName, '2-wallet-connected', report);
        recordAction('Connect wallet', true, undefined, report);
        console.log(`[${persona.shortName}] ✅ Wallet connected`);

        // 3. Mint ETH
        await page.goto(`${STACK_WEBAPP_URL}/app/cheats`);
        // 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);
        await mintEth(page, STACK_RPC_URL, address, persona.ethToMint);
        await takeScreenshot(page, persona.shortName, '3-eth-minted', report);
        recordAction(`Mint ${persona.ethToMint} ETH`, true, undefined, report);
        console.log(`[${persona.shortName}] ✅ Minted ${persona.ethToMint} ETH`);

        // 4. Buy KRK
        await buyKrk(page, persona.ethToSpend);
        await takeScreenshot(page, persona.shortName, '4-krk-purchased', report);
        recordAction(`Buy KRK with ${persona.ethToSpend} ETH`, true, undefined, report);
        console.log(`[${persona.shortName}] ✅ Bought KRK with ${persona.ethToSpend} ETH`);

        // 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);

        // 5. Navigate to stake page
        await page.goto(`${STACK_WEBAPP_URL}/app/stake`);
        // 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(3_000);
        await takeScreenshot(page, persona.shortName, '5-stake-page', report);

        // 6. Stake KRK with known working amount
        const stakeAmount = persona.stakeAmount;
        console.log(`[${persona.shortName}] Attempting to stake ${stakeAmount} KRK at ${persona.taxRate}% tax...`);
        await attemptStake(page, stakeAmount, persona.taxRate, persona.shortName, report);
        await takeScreenshot(page, persona.shortName, '6-stake-complete', report);
        console.log(`[${persona.shortName}] ✅ Staked ${stakeAmount} KRK at ${persona.taxRate}% tax`);

        // 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);

        // 7. Verify position exists
        await page.goto(`${STACK_WEBAPP_URL}/app/stake`);
        // 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);

        const myPositionsSection = page.locator('.my-positions-list, [class*="my-position"], [class*="MyPosition"]').first();
        const hasPosition = await myPositionsSection.isVisible({ timeout: 5_000 }).catch(() => false);

        if (hasPosition) {
          await takeScreenshot(page, persona.shortName, '7-position-verified', report);
          recordAction('Verify staked position exists', true, undefined, report);
          console.log(`[${persona.shortName}] ✅ Position verified in UI`);
        } else {
          await takeScreenshot(page, persona.shortName, '7-position-check-failed', report);
          recordAction('Verify staked position exists', false, 'Position not visible in UI', report);
          console.log(`[${persona.shortName}] ⚠️ Position not visible in UI - may still exist on-chain`);
        }

        report.overallSentiment = `${persona.name} completed full journey: connected wallet → bought KRK → staked → ${hasPosition ? 'verified position' : 'stake attempted but position not visible'}`;
        logObservation(persona.shortName, report.overallSentiment, report);

        console.log(`[${persona.shortName}] ✅ FULL JOURNEY COMPLETE`);

      } catch (error: any) {
        const errorMsg = error.message || String(error);
        console.error(`[${persona.shortName}] ❌ Test failed: ${errorMsg}`);
        await takeScreenshot(page, persona.shortName, 'error-state', report).catch(() => {});
        report.overallSentiment = `Test failed: ${errorMsg}`;
        throw error;
      } finally {
        writeReport(persona.name.toLowerCase().replace(/\s+/g, '-'), report);
        await context.close();
      }
    });
  }
});
