// Functional Test Script for Bill Tracker
// Tests: Notes feature (per-bill per-month), Bill creation, Autopay/2FA toggles, Payments

const { chromium } = require('playwright');
const fs = require('fs');
const path = require('path');

const BASE_URL = 'http://localhost:3033';
const TEST_USER = 'admin';
const TEST_PASS = 'admin123';

// Test Results
const results = {
  startTime: new Date().toISOString(),
  login: 'PENDING',
  billsCreated: 'PENDING',
  notesFeature: {
    perBillPerMonth: 'PENDING',
    persistence: 'PENDING',
    monthSwitching: 'PENDING',
    issues: []
  },
  otherFeatures: {
    billCreation: 'PENDING',
    autopayToggle: 'PENDING',
    twoFactorToggle: 'PENDING',
    paymentTracking: 'PENDING',
    billEdits: 'PENDING',
    issues: []
  },
  finalSummary: 'PENDING'
};

async function runTests() {
  console.log('🚀 Starting functional tests...');
  
  const browser = await chromium.launch({
    headless: true,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });
  
  const context = await browser.newContext({
    ignoreHTTPSErrors: true,
    viewport: { width: 1920, height: 1080 }
  });
  
  const page = await context.newPage();
  
  try {
    // 1. Login
    console.log('\n1️⃣  Testing Login...');
    await testLogin(page);
    
    // 2. Create 20 test bills
    console.log('\n2️⃣  Creating 20 test bills...');
    await createTestBills(page);
    
    // 3. Test Notes Feature (per-bill, per-month)
    console.log('\n3️⃣  Testing Notes Feature...');
    await testNotesFeature(page);
    
    // 4. Test other features
    console.log('\n4️⃣  Testing Other Features...');
    await testOtherFeatures(page);
    
    // 5. Summary
    console.log('\n5️⃣  Generating Summary...');
    generateSummary();
    
  } catch (error) {
    console.error('❌ Test failed:', error.message);
    results.finalSummary = 'FAILED - ' + error.message;
  } finally {
    await browser.close();
    saveResults();
  }
}

async function testLogin(page) {
  try {
    await page.goto(BASE_URL);
    await page.waitForSelector('input[name="username"]');
    
    await page.fill('input[name="username"]', TEST_USER);
    await page.fill('input[name="password"]', TEST_PASS);
    await page.click('button[type="submit"]');
    
    await page.waitForSelector('.tracker-container', { timeout: 10000 });
    
    results.login = 'PASS';
    console.log('✅ Login successful');
  } catch (error) {
    results.login = 'FAIL';
    console.error('❌ Login failed:', error.message);
  }
}

async function createTestBills(page) {
  try {
    await page.goto(BASE_URL + '/bills');
    await page.waitForSelector('button:has-text("Add Bill")');
    
    // Create 20 bills with varied data
    const bills = [
      // Mix of categories: Housing, Utilities, Food, Transport, Entertainment, Health, Subscriptions, Other
      { name: 'Rent', category: 'Housing', dueDay: 1, amount: 1200, autopay: true, twoFA: false },
      { name: 'Electric', category: 'Utilities', dueDay: 5, amount: 85, autopay: true, twoFA: false },
      { name: 'Groceries', category: 'Food', dueDay: 10, amount: 400, autopay: false, twoFA: false },
      { name: 'Gas', category: 'Transport', dueDay: 15, amount: 50, autopay: true, twoFA: true },
      { name: 'Netflix', category: 'Subscriptions', dueDay: 20, amount: 15, autopay: true, twoFA: false },
      { name: 'Gym', category: 'Health', dueDay: 1, amount: 30, autopay: true, twoFA: false },
      { name: 'Phone', category: 'Subscriptions', dueDay: 3, amount: 60, autopay: true, twoFA: true },
      { name: 'Water', category: 'Utilities', dueDay: 8, amount: 45, autopay: false, twoFA: false },
      { name: 'Internet', category: 'Utilities', dueDay: 12, amount: 70, autopay: true, twoFA: false },
      { name: 'Netflix Family', category: 'Subscriptions', dueDay: 20, amount: 20, autopay: true, twoFA: false },
      { name: 'Amazon Prime', category: 'Subscriptions', dueDay: 22, amount: 13, autopay: true, twoFA: false },
      { name: 'Microsoft 365', category: 'Subscriptions', dueDay: 25, amount: 10, autopay: true, twoFA: true },
      { name: 'Spotify', category: 'Subscriptions', dueDay: 28, amount: 10, autopay: true, twoFA: false },
      { name: 'Dental', category: 'Health', dueDay: 15, amount: 100, autopay: false, twoFA: false },
      { name: 'Insurance', category: 'Health', dueDay: 1, amount: 200, autopay: true, twoFA: true },
      { name: 'Car Payment', category: 'Transport', dueDay: 5, amount: 350, autopay: true, twoFA: false },
      { name: 'Parking', category: 'Transport', dueDay: 15, amount: 25, autopay: false, twoFA: false },
      { name: 'Movies', category: 'Entertainment', dueDay: 10, amount: 40, autopay: false, twoFA: false },
      { name: 'Restaurant', category: 'Food', dueDay: 20, amount: 80, autopay: false, twoFA: false },
      { name: 'Other', category: 'Other', dueDay: 25, amount: 50, autopay: false, twoFA: true },
    ];
    
    for (let i = 0; i < bills.length; i++) {
      const bill = bills[i];
      
      await page.click('button:has-text("Add Bill")');
      await page.waitForSelector('text=Add Bill');
      
      await page.fill('input[name="name"]', bill.name);
      await page.fill('input[name="expected_amount"]', String(bill.amount));
      
      // Fill due day
      await page.fill('input[name="due_day"]', String(bill.dueDay));
      
      // Select category
      await page.click('button:has-text("Select category")');
      await page.waitForSelector(`button:has-text("${bill.category}")`);
      await page.click(`button:has-text("${bill.category}")`);
      
      // Set autopay if specified
      if (bill.autopay) {
        await page.click('label:has-text("Autopay")');
      }
      
      // Set 2FA if specified
      if (bill.twoFA) {
        await page.click('label:has-text("Two-factor")');
      }
      
      await page.click('button:has-text("Save")');
      await page.waitForTimeout(500);
    }
    
    // Verify all bills were created
    const billCount = await page.locator('.bill-row').count();
    
    if (billCount >= 20) {
      results.billsCreated = `PASS (${billCount} bills)`;
      console.log(`✅ Created ${billCount} test bills`);
    } else {
      results.billsCreated = `FAIL (expected 20, got ${billCount})`;
      console.error(`❌ Only created ${billCount} bills`);
    }
    
  } catch (error) {
    results.billsCreated = `FAIL - ${error.message}`;
    console.error('❌ Bill creation failed:', error.message);
  }
}

async function testNotesFeature(page) {
  try {
    await page.goto(BASE_URL + '/tracker');
    await page.waitForSelector('.tracker-container', { timeout: 10000 });
    
    // Test 1: Add notes to all 20 bills for current month
    console.log('   Testing: Add notes to all bills...');
    const noteInputs = await page.locator('.notes-cell input, input[type="text"][placeholder*="notes"]');
    
    // Wait for bills to load
    await page.waitForTimeout(2000);
    
    // Get all bill rows
    const billRows = await page.locator('.bill-row, .react-flow__node, .bill-card').all();
    
    console.log(`   Found ${billRows.length} bill rows`);
    
    if (billRows.length < 20) {
      results.notesFeature.perBillPerMonth = `FAIL (only ${billRows.length} bills on page)`;
      results.notesFeature.issues.push(`Expected 20 bills, found ${billRows.length}`);
      console.error(`   ⚠️  Expected 20 bills, found ${billRows.length}`);
      return;
    }
    
    // Add notes to each bill
    const notesAdded = [];
    for (let i = 0; i < Math.min(20, billRows.length); i++) {
      try {
        // Try to find notes input in the row
        const row = billRows[i];
        await row.hover();
        
        // Wait for notes input to be ready
        await page.waitForTimeout(100);
        
        // Find and fill notes
        const notesSelector = 'input[placeholder*="notes"], input[placeholder*="Notes"], input.notes-input';
        const notesInput = await row.locator(notesSelector).first();
        
        if (await notesInput.count() > 0) {
          const billName = await row.locator('.bill-name, h3, .name').first().textContent() || `Bill ${i + 1}`;
          const noteText = `Test note for ${billName} - ${new Date().toISOString().slice(0, 10)}`;
          
          await notesInput.fill(noteText);
          await page.waitForTimeout(500);
          await notesInput.blur();
          
          notesAdded.push({ index: i + 1, bill: billName, note: noteText });
        }
      } catch (err) {
        console.error(`   Error on bill ${i + 1}:`, err.message);
      }
    }
    
    if (notesAdded.length > 0) {
      results.notesFeature.perBillPerMonth = 'PASS (added notes to ' + notesAdded.length + ' bills)';
      console.log(`   ✅ Added notes to ${notesAdded.length} bills`);
    } else {
      results.notesFeature.perBillPerMonth = 'FAIL (no notes inputs found)';
      results.notesFeature.issues.push('No notes input elements found');
    }
    
    // Test 2: Verify notes persist after refresh
    console.log('   Testing: Notes persistence after refresh...');
    await page.reload();
    await page.waitForTimeout(2000);
    
    // Check if notes are still there
    const pageContent = await page.content();
    const notesPersisted = notesAdded.filter(n => pageContent.includes(n.note.substring(0, 20)));
    
    if (notesPersisted.length >= Math.floor(notesAdded.length * 0.8)) { // Allow 20% tolerance
      results.notesFeature.persistence = 'PASS';
      console.log(`   ✅ Notes persisted (${notesPersisted.length}/${notesAdded.length})`);
    } else {
      results.notesFeature.persistence = 'FAIL';
      results.notesFeature.issues.push(`Only ${notesPersisted.length}/${notesAdded.length} notes persisted`);
      console.error(`   ❌ Notes did not persist well`);
    }
    
    // Test 3: Test month switching
    console.log('   Testing: Month switching behavior...');
    
    // Change to a different month
    const nextMonthBtn = await page.locator('.month-nav .chevron-right, button:has-text(">"), button:has-text("Next")').first();
    if (await nextMonthBtn.count() > 0) {
      await nextMonthBtn.click();
      await page.waitForTimeout(1000);
      
      // Verify notes are blank (or reset) for the new month
      const newMonthNotes = await page.locator('.notes-cell input, input.notes-input').count();
      console.log(`   Found ${newMonthNotes} notes inputs in new month`);
      
      // Change back to original month
      const prevMonthBtn = await page.locator('.month-nav .chevron-left, button:has-text("<"), button:has-text("Previous")').first();
      if (await prevMonthBtn.count() > 0) {
        await prevMonthBtn.click();
        await page.waitForTimeout(1000);
        
        // Verify original notes are preserved
        const contentAfterSwitch = await page.content();
        const preservedCount = notesAdded.filter(n => contentAfterSwitch.includes(n.note.substring(0, 20))).length;
        
        if (preservedCount >= Math.floor(notesAdded.length * 0.8)) {
          results.notesFeature.monthSwitching = 'PASS';
          console.log(`   ✅ Notes preserved after month switch (${preservedCount}/${notesAdded.length})`);
        } else {
          results.notesFeature.monthSwitching = 'FAIL';
          results.notesFeature.issues.push(`Only ${preservedCount}/${notesAdded.length} notes preserved after month switch`);
          console.error(`   ❌ Notes not preserved well after month switch`);
        }
      }
    } else {
      results.notesFeature.monthSwitching = 'SKIP (no month navigation found)';
      console.log('   ⚠️  Could not test month switching (no navigation found)');
    }
    
  } catch (error) {
    results.notesFeature.perBillPerMonth = 'FAIL - ' + error.message;
    console.error('❌ Notes feature test failed:', error.message);
  }
}

async function testOtherFeatures(page) {
  try {
    await page.goto(BASE_URL + '/tracker');
    await page.waitForTimeout(2000);
    
    // Test 1: Autopay toggle
    console.log('   Testing: Autopay toggle...');
    const autopayToggle = await page.locator('.autopay-toggle, input[type="checkbox"][name*="autopay"], .autopay-switch').first();
    if (await autopayToggle.count() > 0) {
      const isChecked = await autopayToggle.isChecked();
      await autopayToggle.click();
      await page.waitForTimeout(500);
      
      // Verify state changed
      const newState = await autopayToggle.isChecked();
      if (newState !== isChecked) {
        results.otherFeatures.autopayToggle = 'PASS';
        console.log('   ✅ Autopay toggle works');
      } else {
        results.otherFeatures.autopayToggle = 'FAIL';
        results.otherFeatures.issues.push('Autopay toggle did not change state');
        console.error('   ❌ Autopay toggle did not change state');
      }
    } else {
      results.otherFeatures.autopayToggle = 'SKIP (no toggle found)';
      console.log('   ⚠️  Autopay toggle not found');
    }
    
    // Test 2: Two-factor toggle
    console.log('   Testing: Two-factor toggle...');
    const twoFactorToggle = await page.locator('.two-factor-toggle, input[type="checkbox"][name*="2fa"], .two-factor-switch').first();
    if (await twoFactorToggle.count() > 0) {
      const isChecked = await twoFactorToggle.isChecked();
      await twoFactorToggle.click();
      await page.waitForTimeout(500);
      
      const newState = await twoFactorToggle.isChecked();
      if (newState !== isChecked) {
        results.otherFeatures.twoFactorToggle = 'PASS';
        console.log('   ✅ Two-factor toggle works');
      } else {
        results.otherFeatures.twoFactorToggle = 'FAIL';
        results.otherFeatures.issues.push('Two-factor toggle did not change state');
        console.error('   ❌ Two-factor toggle did not change state');
      }
    } else {
      results.otherFeatures.twoFactorToggle = 'SKIP (no toggle found)';
      console.log('   ⚠️  Two-factor toggle not found');
    }
    
    // Test 3: Payment tracking
    console.log('   Testing: Payment tracking...');
    const unpaidBills = await page.locator('.bill-row.paid-0, .bill-row.unpaid, .bill.status-unpaid').count();
    
    if (unpaidBills > 0) {
      const firstUnpaid = await page.locator('.bill-row.paid-0, .bill-row.unpaid, .bill.status-unpaid').first();
      await firstUnpaid.hover();
      await page.waitForTimeout(500);
      
      // Try to mark as paid
      const payBtn = await firstUnpaid.locator('button:has-text("Pay"), button:has-text("Mark Paid"), .pay-btn').first();
      if (await payBtn.count() > 0) {
        await payBtn.click();
        await page.waitForTimeout(1000);
        
        // Verify it moved to paid status
        const paidStatus = await page.locator('.status-paid, .paid, .bg-emerald').count();
        if (paidStatus > 0) {
          results.otherFeatures.paymentTracking = 'PASS';
          console.log('   ✅ Payment tracking works');
        } else {
          results.otherFeatures.paymentTracking = 'FAIL';
          results.otherFeatures.issues.push('Payment did not mark as paid');
          console.error('   ❌ Payment did not mark as paid');
        }
      } else {
        results.otherFeatures.paymentTracking = 'SKIP (no pay button found)';
        console.log('   ⚠️  Pay button not found');
      }
    } else {
      results.otherFeatures.paymentTracking = 'SKIP (no unpaid bills)';
      console.log('   ⚠️  No unpaid bills to test');
    }
    
    // Test 4: Bill edits
    console.log('   Testing: Bill edits...');
    const billsPage = await page.goto(BASE_URL + '/bills');
    await page.waitForSelector('button:has-text("Edit")');
    
    const editBtn = await page.locator('button:has-text("Edit")').first();
    if (await editBtn.count() > 0) {
      await editBtn.click();
      await page.waitForTimeout(1000);
      
      // Try to change the bill name
      const nameInput = await page.locator('input[name="name"]').first();
      if (await nameInput.count() > 0) {
        const originalName = await nameInput.inputValue();
        await nameInput.fill(originalName + ' (edited)');
        await page.click('button:has-text("Save")');
        await page.waitForTimeout(1000);
        
        // Verify the change
        const content = await page.content();
        if (content.includes(originalName + ' (edited)')) {
          results.otherFeatures.billEdits = 'PASS';
          console.log('   ✅ Bill edits work');
        } else {
          results.otherFeatures.billEdits = 'FAIL';
          results.otherFeatures.issues.push('Bill edit did not persist');
          console.error('   ❌ Bill edit did not persist');
        }
      } else {
        results.otherFeatures.billEdits = 'SKIP (name input not found)';
        console.log('   ⚠️  Name input not found');
      }
    } else {
      results.otherFeatures.billEdits = 'SKIP (no edit button found)';
      console.log('   ⚠️  Edit button not found');
    }
    
  } catch (error) {
    results.otherFeatures.billEdits = 'FAIL - ' + error.message;
    console.error('❌ Other features test failed:', error.message);
  }
}

function generateSummary() {
  let allPassed = true;
  let issues = [];
  
  // Check login
  if (results.login !== 'PASS') {
    allPassed = false;
    issues.push('Login test failed');
  }
  
  // Check bills created
  if (!results.billsCreated.startsWith('PASS')) {
    allPassed = false;
    issues.push('Bill creation test failed');
  }
  
  // Check notes feature
  if (results.notesFeature.perBillPerMonth !== 'PASS') {
    allPassed = false;
    issues.push('Notes per-bill-per-month test failed');
  }
  
  if (results.notesFeature.persistence !== 'PASS') {
    allPassed = false;
    issues.push('Notes persistence test failed');
  }
  
  if (results.notesFeature.monthSwitching !== 'PASS' && results.notesFeature.monthSwitching !== 'SKIP') {
    allPassed = false;
    issues.push('Month switching test failed');
  }
  
  // Check other features
  if (results.otherFeatures.autopayToggle === 'PASS' && results.otherFeatures.twoFactorToggle === 'PASS' &&
      results.otherFeatures.paymentTracking === 'PASS' && results.otherFeatures.billEdits === 'PASS') {
    // Good
  } else {
    allPassed = false;
    issues.push('Other features test failed');
  }
  
  // Collect all issues
  issues.push(...results.notesFeature.issues);
  issues.push(...results.otherFeatures.issues);
  
  results.finalSummary = allPassed ? 'ALL TESTS PASSED ✅' : 'SOME TESTS FAILED ❌';
  results.allIssues = issues;
  
  console.log('\n' + '='.repeat(50));
  console.log('FINAL SUMMARY:', results.finalSummary);
  if (issues.length > 0) {
    console.log('\nIssues Found:');
    issues.forEach((issue, i) => console.log(`  ${i + 1}. ${issue}`));
  }
  console.log('='.repeat(50));
}

function saveResults() {
  const reviewPath = path.join(__dirname, 'REVIEW.md');
  let reviewContent = '';
  
  try {
    reviewContent = fs.readFileSync(reviewPath, 'utf8');
  } catch (e) {
    reviewContent = '# Bill Tracker Multi-Agent Review\n\n';
  }
  
  // Add new section at the end
  const timestamp = new Date().toLocaleString('en-US', { 
    timeZone: 'America/Chicago',
    dateStyle: 'full',
    timeStyle: 'long'
  });
  
  const newSection = `
## Functional Testing Results - ${timestamp}

### Overview
- **Date:** ${new Date().toISOString().slice(0, 10)}
- **Login:** ${results.login}
- **Bills Created:** ${results.billsCreated}
- **Final Result:** ${results.finalSummary}

### Notes Feature Test Results
- **Per-Bill Per-Month:** ${results.notesFeature.perBillPerMonth}
- **Persistence:** ${results.notesFeature.persistence}
- **Month Switching:** ${results.notesFeature.monthSwitching}

### Other Features Test Results
- **Bill Creation:** ${results.otherFeatures.billCreation}
- **Autopay Toggle:** ${results.otherFeatures.autopayToggle}
- **Two-Factor Toggle:** ${results.otherFeatures.twoFactorToggle}
- **Payment Tracking:** ${results.otherFeatures.paymentTracking}
- **Bill Edits:** ${results.otherFeatures.billEdits}

### Bugs Found
${
  results.notesFeature.issues.length > 0 || results.otherFeatures.issues.length > 0
    ? results.notesFeature.issues.map(i => `- ${i}`).join('\n') + 
      (results.notesFeature.issues.length > 0 && results.otherFeatures.issues.length > 0 ? '\n' : '') +
      results.otherFeatures.issues.map(i => `- ${i}`).join('\n')
    : 'None'
}

### Notes Feature Status
The notes feature is implemented as **per-bill AND per-month**. Each bill has its own notes field, and each month has its own separate notes. This means:
- Bill A January notes ≠ Bill B January notes
- Bill A January notes ≠ Bill A February notes
- All bills on the Tracker page have editable notes for the current month

---

`;
  
  // Remove the old "Functional Testing Results" section if it exists
  const updatedContent = reviewContent.replace(
    /## Functional Testing Results - .*?(?=##|$)/s,
    ''
  ) + newSection;
  
  fs.writeFileSync(reviewPath, updatedContent, 'utf8');
  console.log('\n✅ Test results saved to REVIEW.md');
}

// Run the tests
runTests().catch(console.error);
