import { test, expect, type APIRequestContext } from '@playwright/test';
import { Wallet } from 'ethers';
import { createWalletContext } from '../setup/wallet-provider';
import { getStackConfig, validateStackHealthy } from '../setup/stack';

const ACCOUNT_PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
const ACCOUNT_ADDRESS = new Wallet(ACCOUNT_PRIVATE_KEY).address;

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

/**
 * Fetch holder data from GraphQL
 */
async function fetchHolder(request: APIRequestContext, address: string) {
  const response = await request.post(STACK_GRAPHQL_URL, {
    data: {
      query: `query { holders(address: "${address.toLowerCase()}") { address balance } }`,
    },
    headers: { 'content-type': 'application/json' },
  });
  const payload = await response.json();
  return payload?.data?.holders;
}

/**
 * Fetch active positions for an owner from GraphQL
 */
async function fetchPositions(request: APIRequestContext, owner: string) {
  const response = await request.post(STACK_GRAPHQL_URL, {
    data: {
      query: `query {
        positionss(where: { owner: "${owner.toLowerCase()}", status: "Active" }, limit: 5) {
          items { id owner taxRate kraikenDeposit status share }
        }
      }`,
    },
    headers: { 'content-type': 'application/json' },
  });
  const payload = await response.json();
  return payload?.data?.positionss?.items ?? [];
}

test.describe('Dashboard Pages', () => {
  test.beforeAll(async ({ request }) => {
    await validateStackHealthy(STACK_CONFIG);

    // Wait for ponder to index positions created by earlier tests (01-05).
    // Ponder runs in realtime mode but may lag a few seconds behind the chain.
    const maxWaitMs = 30_000;
    const pollMs = 1_000;
    const start = Date.now();
    let found = false;
    while (Date.now() - start < maxWaitMs) {
      const positions = await fetchPositions(request, ACCOUNT_ADDRESS);
      if (positions.length > 0) {
        found = true;
        console.log(`[TEST] Ponder has ${positions.length} positions after ${Date.now() - start}ms`);
        break;
      }
      // eslint-disable-next-line no-restricted-syntax -- no event source exists for Ponder indexing lag and UI re-renders; Promise+setTimeout used for polling Ponder over HTTP where no push subscription is available. See AGENTS.md #Engineering Principles.
      await new Promise(r => setTimeout(r, pollMs));
    }
    if (!found) {
      console.log('[TEST] WARNING: No positions found in ponder after 30s — tests may fail');
    }
  });

  test.describe('Wallet Dashboard', () => {
    test('renders wallet page with balance and protocol stats', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });
      const page = await context.newPage();
      const errors: string[] = [];
      page.on('console', msg => {
        if (msg.type() === 'error') errors.push(msg.text());
      });

      try {
        await page.goto(`${STACK_WEBAPP_URL}/app/wallet/${ACCOUNT_ADDRESS}`, {
          waitUntil: 'domcontentloaded',
        });
        await page.waitForLoadState('networkidle');
        // eslint-disable-next-line no-restricted-syntax -- no event source exists for Ponder indexing lag and UI re-renders; Promise+setTimeout used for polling Ponder over HTTP where no push subscription is available. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2000);

        // Should show the address (truncated)
        const addressText = await page.textContent('body');
        expect(addressText).toContain(ACCOUNT_ADDRESS.slice(0, 6));

        // Should show KRK balance (non-zero after test 01 mints + swaps)
        const balanceEl = page.locator('text=/\\d+.*KRK/i').first();
        await expect(balanceEl).toBeVisible({ timeout: 10_000 });

        // Should show ETH backing card
        const ethBacking = page.locator('text=/ETH Backing/i').first();
        await expect(ethBacking).toBeVisible({ timeout: 5_000 });

        // Should show floor value card
        const floorValue = page.locator('text=/Floor Value/i').first();
        await expect(floorValue).toBeVisible({ timeout: 5_000 });

        // Should show protocol health metrics
        const ethReserve = page.locator('text=/ETH Reserve/i').first();
        await expect(ethReserve).toBeVisible({ timeout: 5_000 });

        // Take screenshot
        await page.screenshot({
          path: 'test-results/dashboard-wallet.png',
          fullPage: true,
        });

        // No console errors
        const realErrors = errors.filter(
          e => !e.includes('favicon') && !e.includes('DevTools')
        );
        expect(realErrors).toHaveLength(0);

        console.log('[TEST] ✅ Wallet dashboard renders correctly');
      } finally {
        await page.close();
        await context.close();
      }
    });

    test('wallet page shows staking positions when they exist', async ({ browser, request }) => {
      // First verify positions exist (created by test 01)
      const positions = await fetchPositions(request, ACCOUNT_ADDRESS);
      console.log(`[TEST] Found ${positions.length} positions for ${ACCOUNT_ADDRESS}`);

      if (positions.length === 0) {
        console.log('[TEST] ⚠️ No positions found — skipping position list check');
        test.skip();
        return;
      }

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

      try {
        await page.goto(`${STACK_WEBAPP_URL}/app/wallet/${ACCOUNT_ADDRESS}`, {
          waitUntil: 'domcontentloaded',
        });
        await page.waitForLoadState('networkidle');
        // eslint-disable-next-line no-restricted-syntax -- no event source exists for Ponder indexing lag and UI re-renders; Promise+setTimeout used for polling Ponder over HTTP where no push subscription is available. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2000);

        // Should show position entries with links to position detail
        const positionLink = page.locator(`a[href*="/position/"]`).first();
        await expect(positionLink).toBeVisible({ timeout: 10_000 });

        console.log('[TEST] ✅ Wallet dashboard shows staking positions');
      } finally {
        await page.close();
        await context.close();
      }
    });

    test('wallet page handles unknown address gracefully', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });
      const page = await context.newPage();
      const errors: string[] = [];
      page.on('console', msg => {
        if (msg.type() === 'error') errors.push(msg.text());
      });

      try {
        // Navigate to a wallet with no balance
        const unknownAddr = '0x0000000000000000000000000000000000000001';
        await page.goto(`${STACK_WEBAPP_URL}/app/wallet/${unknownAddr}`, {
          waitUntil: 'domcontentloaded',
        });
        await page.waitForLoadState('networkidle');
        // eslint-disable-next-line no-restricted-syntax -- no event source exists for Ponder indexing lag and UI re-renders; Promise+setTimeout used for polling Ponder over HTTP where no push subscription is available. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2000);

        // Page should render without crashing
        const body = await page.textContent('body');
        expect(body).toBeTruthy();

        // Should show zero or empty state (not crash)
        const realErrors = errors.filter(
          e => !e.includes('favicon') && !e.includes('DevTools')
        );
        expect(realErrors).toHaveLength(0);

        console.log('[TEST] ✅ Wallet page handles unknown address gracefully');
      } finally {
        await page.close();
        await context.close();
      }
    });
  });

  test.describe('Position Dashboard', () => {
    test('renders position page with valid position data', async ({ browser, request }) => {
      // Find a real position ID from GraphQL
      const positions = await fetchPositions(request, ACCOUNT_ADDRESS);
      console.log(`[TEST] Found ${positions.length} positions`);

      if (positions.length === 0) {
        console.log('[TEST] ⚠️ No positions found — skipping');
        test.skip();
        return;
      }

      const positionId = positions[0].id;
      console.log(`[TEST] Testing position #${positionId}`);

      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });
      const page = await context.newPage();
      const errors: string[] = [];
      page.on('console', msg => {
        if (msg.type() === 'error') errors.push(msg.text());
      });

      try {
        await page.goto(`${STACK_WEBAPP_URL}/app/position/${positionId}`, {
          waitUntil: 'domcontentloaded',
        });
        await page.waitForLoadState('networkidle');
        // eslint-disable-next-line no-restricted-syntax -- no event source exists for Ponder indexing lag and UI re-renders; Promise+setTimeout used for polling Ponder over HTTP where no push subscription is available. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2000);

        // Should show position ID
        const body = await page.textContent('body');
        expect(body).toContain(positionId);

        // Should show deposit amount
        const deposited = page.locator('text=/Deposited/i').first();
        await expect(deposited).toBeVisible({ timeout: 10_000 });

        // Should show current value
        const currentValue = page.locator('text=/Current Value/i').first();
        await expect(currentValue).toBeVisible({ timeout: 5_000 });

        // Should show tax cost
        const taxPaid = page.locator('text=/Tax Cost/i').first();
        await expect(taxPaid).toBeVisible({ timeout: 5_000 });

        // Should show net return
        const netReturn = page.locator('text=/Net Return/i').first();
        await expect(netReturn).toBeVisible({ timeout: 5_000 });

        // Should show tax rate
        const taxRate = page.locator('text=/Tax Rate/i').first();
        await expect(taxRate).toBeVisible({ timeout: 5_000 });

        // Should show snatch risk indicator
        const snatchRisk = page.locator('text=/Snatch Risk/i').first();
        await expect(snatchRisk).toBeVisible({ timeout: 5_000 });

        // Should show daily tax cost
        const dailyTax = page.locator('text=/Daily Tax/i').first();
        await expect(dailyTax).toBeVisible({ timeout: 5_000 });

        // Should show owner link to wallet page
        const ownerLink = page.locator('a[href*="/wallet/"]').first();
        await expect(ownerLink).toBeVisible({ timeout: 5_000 });

        // Take screenshot
        await page.screenshot({
          path: 'test-results/dashboard-position.png',
          fullPage: true,
        });

        // No console errors
        const realErrors = errors.filter(
          e => !e.includes('favicon') && !e.includes('DevTools')
        );
        expect(realErrors).toHaveLength(0);

        console.log('[TEST] ✅ Position dashboard renders correctly');
      } finally {
        await page.close();
        await context.close();
      }
    });

    test('position page handles non-existent position gracefully', async ({ browser }) => {
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });
      const page = await context.newPage();
      const errors: string[] = [];
      page.on('console', msg => {
        if (msg.type() === 'error') errors.push(msg.text());
      });

      try {
        await page.goto(`${STACK_WEBAPP_URL}/app/position/999999999`, {
          waitUntil: 'domcontentloaded',
        });
        await page.waitForLoadState('networkidle');
        // eslint-disable-next-line no-restricted-syntax -- no event source exists for Ponder indexing lag and UI re-renders; Promise+setTimeout used for polling Ponder over HTTP where no push subscription is available. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2000);

        // Should show "not found" state without crashing
        const body = await page.textContent('body');
        expect(body).toBeTruthy();
        // Look for not-found or error messaging
        const hasNotFound = body?.toLowerCase().includes('not found') ||
          body?.toLowerCase().includes('no position') ||
          body?.toLowerCase().includes('does not exist');
        expect(hasNotFound).toBeTruthy();

        const realErrors = errors.filter(
          e => !e.includes('favicon') && !e.includes('DevTools')
        );
        expect(realErrors).toHaveLength(0);

        console.log('[TEST] ✅ Position page handles non-existent ID gracefully');
      } finally {
        await page.close();
        await context.close();
      }
    });

    test('position page links back to wallet dashboard', async ({ browser, request }) => {
      const positions = await fetchPositions(request, ACCOUNT_ADDRESS);
      if (positions.length === 0) {
        console.log('[TEST] ⚠️ No positions — skipping');
        test.skip();
        return;
      }

      const positionId = positions[0].id;
      const context = await createWalletContext(browser, {
        privateKey: ACCOUNT_PRIVATE_KEY,
        rpcUrl: STACK_RPC_URL,
      });
      const page = await context.newPage();

      try {
        await page.goto(`${STACK_WEBAPP_URL}/app/position/${positionId}`, {
          waitUntil: 'domcontentloaded',
        });
        await page.waitForLoadState('networkidle');
        // eslint-disable-next-line no-restricted-syntax -- no event source exists for Ponder indexing lag and UI re-renders; Promise+setTimeout used for polling Ponder over HTTP where no push subscription is available. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2000);

        // Click owner link → should navigate to wallet page
        const ownerLink = page.locator('a[href*="/wallet/"]').first();
        await expect(ownerLink).toBeVisible({ timeout: 10_000 });
        await ownerLink.click();
        await page.waitForLoadState('networkidle');
        // eslint-disable-next-line no-restricted-syntax -- no event source exists for Ponder indexing lag and UI re-renders; Promise+setTimeout used for polling Ponder over HTTP where no push subscription is available. See AGENTS.md #Engineering Principles.
        await page.waitForTimeout(2000);

        // Should now be on the wallet page
        expect(page.url()).toContain('/wallet/');

        console.log('[TEST] ✅ Position → Wallet navigation works');
      } finally {
        await page.close();
        await context.close();
      }
    });
  });
});
