import { test, expect, Page } from '@playwright/test';
import * as path from 'path';
import * as fs from 'fs';

// Test data
const testEmail = `user+e2e${Date.now()}@lab.veza`;
const testPassword = `V3za!e2e-${Date.now()}`;
const sessionFile = path.join(__dirname, '../../.session-e2e.json');

// Helper functions
async function saveSession(page: Page) {
  const localStorage = await page.evaluate(() => {
    return {
      access_token: window.localStorage.getItem('access_token'),
      refresh_token: window.localStorage.getItem('refresh_token'),
      user: window.localStorage.getItem('user'),
    };
  });
  
  fs.writeFileSync(sessionFile, JSON.stringify(localStorage, null, 2));
}

async function loadSession(page: Page) {
  if (fs.existsSync(sessionFile)) {
    const session = JSON.parse(fs.readFileSync(sessionFile, 'utf-8'));
    await page.evaluate((session) => {
      if (session.access_token) window.localStorage.setItem('access_token', session.access_token);
      if (session.refresh_token) window.localStorage.setItem('refresh_token', session.refresh_token);
      if (session.user) window.localStorage.setItem('user', session.user);
    }, session);
  }
}

test.describe('Authentication Flow', () => {
  test.beforeEach(async ({ page }) => {
    // Clear storage
    await page.context().clearCookies();
    await page.evaluate(() => window.localStorage.clear());
  });

  test('should show login page for unauthenticated users', async ({ page }) => {
    await page.goto('/');
    
    // Should redirect to login
    await expect(page).toHaveURL(/\/(login|auth)/);
    
    // Check for login form elements
    await expect(page.locator('input[type="email"], input[name="email"]')).toBeVisible();
    await expect(page.locator('input[type="password"], input[name="password"]')).toBeVisible();
    await expect(page.locator('button[type="submit"], button:has-text("Login"), button:has-text("Sign in")')).toBeVisible();
  });

  test('should show validation errors for invalid inputs', async ({ page }) => {
    await page.goto('/login');
    
    // Try to submit empty form
    await page.locator('button[type="submit"], button:has-text("Login")').click();
    
    // Should show validation errors
    await expect(page.locator('text=/email.*required/i')).toBeVisible({ timeout: 5000 });
    
    // Try invalid email
    await page.fill('input[type="email"]', 'invalid-email');
    await page.fill('input[type="password"]', 'short');
    await page.locator('button[type="submit"]').click();
    
    // Should show email validation error
    await expect(page.locator('text=/invalid.*email/i')).toBeVisible({ timeout: 5000 });
  });

  test('should register new user successfully', async ({ page }) => {
    await page.goto('/register');
    
    // Fill registration form
    await page.fill('input[type="email"]', testEmail);
    await page.fill('input[type="password"]', testPassword);
    
    // Check for password confirmation field
    const confirmField = page.locator('input[name="confirmPassword"], input[name="password_confirmation"]');
    if (await confirmField.isVisible()) {
      await confirmField.fill(testPassword);
    }
    
    // Submit form
    await page.locator('button[type="submit"], button:has-text("Register"), button:has-text("Sign up")').click();
    
    // Should redirect to dashboard or show success
    await expect(page).toHaveURL(/\/(dashboard|home|app)/, { timeout: 10000 });
    
    // Save session
    await saveSession(page);
    
    // Verify user is logged in
    await expect(page.locator('text=/logout|sign out/i')).toBeVisible({ timeout: 5000 });
  });

  test('should prevent duplicate registration', async ({ page }) => {
    await page.goto('/register');
    
    // Try to register with same email
    await page.fill('input[type="email"]', testEmail);
    await page.fill('input[type="password"]', testPassword);
    
    const confirmField = page.locator('input[name="confirmPassword"], input[name="password_confirmation"]');
    if (await confirmField.isVisible()) {
      await confirmField.fill(testPassword);
    }
    
    await page.locator('button[type="submit"]').click();
    
    // Should show error
    await expect(page.locator('text=/already.*exist|already.*registered|duplicate/i')).toBeVisible({ timeout: 5000 });
  });

  test('should login with valid credentials', async ({ page }) => {
    await page.goto('/login');
    
    // Fill login form
    await page.fill('input[type="email"]', testEmail);
    await page.fill('input[type="password"]', testPassword);
    
    // Submit
    await page.locator('button[type="submit"], button:has-text("Login")').click();
    
    // Should redirect to dashboard
    await expect(page).toHaveURL(/\/(dashboard|home|app)/, { timeout: 10000 });
    
    // Save session
    await saveSession(page);
    
    // Verify user is logged in
    await expect(page.locator('text=/logout|sign out/i')).toBeVisible({ timeout: 5000 });
  });

  test('should show error for invalid credentials', async ({ page }) => {
    await page.goto('/login');
    
    // Try wrong password
    await page.fill('input[type="email"]', testEmail);
    await page.fill('input[type="password"]', 'WrongPassword123!');
    await page.locator('button[type="submit"]').click();
    
    // Should show error
    await expect(page.locator('text=/invalid.*credentials|wrong.*password|authentication.*failed/i')).toBeVisible({ timeout: 5000 });
  });

  test('should handle token refresh', async ({ page }) => {
    // Load previous session
    await loadSession(page);
    
    // Go to protected page
    await page.goto('/dashboard');
    
    // Should still be authenticated
    await expect(page).toHaveURL(/\/(dashboard|home|app)/);
    
    // Simulate token expiry by modifying localStorage
    await page.evaluate(() => {
      const token = window.localStorage.getItem('access_token');
      if (token) {
        // Modify token to make it invalid
        window.localStorage.setItem('access_token', token + '_expired');
      }
    });
    
    // Trigger an API call that should refresh the token
    await page.reload();
    
    // Should either still work (refresh successful) or redirect to login
    const url = page.url();
    expect(url).toMatch(/\/(dashboard|home|app|login)/);
  });

  test('should logout successfully', async ({ page }) => {
    // Load session and login
    await loadSession(page);
    await page.goto('/dashboard');
    
    // Find and click logout
    const logoutButton = page.locator('button:has-text("Logout"), a:has-text("Logout"), button:has-text("Sign out")');
    await logoutButton.click();
    
    // Should redirect to login
    await expect(page).toHaveURL(/\/(login|auth)/, { timeout: 5000 });
    
    // Should clear session
    const localStorage = await page.evaluate(() => {
      return {
        access_token: window.localStorage.getItem('access_token'),
        refresh_token: window.localStorage.getItem('refresh_token'),
      };
    });
    
    expect(localStorage.access_token).toBeNull();
    expect(localStorage.refresh_token).toBeNull();
  });

  test('should handle remember me functionality', async ({ page }) => {
    await page.goto('/login');
    
    // Check if remember me exists
    const rememberMe = page.locator('input[type="checkbox"][name="remember"], label:has-text("Remember me")');
    
    if (await rememberMe.isVisible()) {
      await rememberMe.check();
    }
    
    // Login
    await page.fill('input[type="email"]', testEmail);
    await page.fill('input[type="password"]', testPassword);
    await page.locator('button[type="submit"]').click();
    
    // Wait for redirect
    await expect(page).toHaveURL(/\/(dashboard|home|app)/, { timeout: 10000 });
    
    // Check if cookies are set with longer expiry
    const cookies = await page.context().cookies();
    const authCookie = cookies.find(c => c.name.includes('auth') || c.name.includes('session'));
    
    if (authCookie) {
      // Cookie should have expiry set (not session cookie)
      expect(authCookie.expires).toBeGreaterThan(Date.now() / 1000);
    }
  });

  test('should handle social login buttons', async ({ page }) => {
    await page.goto('/login');
    
    // Check for social login buttons
    const googleButton = page.locator('button:has-text("Google"), a:has-text("Google")');
    const githubButton = page.locator('button:has-text("GitHub"), a:has-text("GitHub")');
    
    // Test visibility (they might not be implemented)
    const hasGoogle = await googleButton.isVisible().catch(() => false);
    const hasGithub = await githubButton.isVisible().catch(() => false);
    
    if (hasGoogle) {
      // Click should navigate to OAuth provider
      const [popup] = await Promise.all([
        page.waitForEvent('popup'),
        googleButton.click()
      ]).catch(() => [null]);
      
      if (popup) {
        expect(popup.url()).toContain('google.com');
        await popup.close();
      }
    }
    
    if (hasGithub) {
      const [popup] = await Promise.all([
        page.waitForEvent('popup'),
        githubButton.click()
      ]).catch(() => [null]);
      
      if (popup) {
        expect(popup.url()).toContain('github.com');
        await popup.close();
      }
    }
  });
});

// Cleanup
test.afterAll(() => {
  if (fs.existsSync(sessionFile)) {
    fs.unlinkSync(sessionFile);
  }
});