#!/usr/bin/env node

/**
 * Reonomy Scraper v11 - PLAYWRIGHT VERSION
 *
 * Why Playwright?
 * - Built-in auto-waiting (no arbitrary sleeps)
 * - Better selectors and element detection
 * - Faster execution
 * - More reliable for dynamic content
 *
 * Features:
 * - Filters for phone and email in advanced search > owner section
 * - Intelligent waiting for contact details (up to 30s)
 * - Uses waitForFunction() instead of polling loops
 */

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

// Configuration
const REONOMY_EMAIL = process.env.REONOMY_EMAIL || 'henry@realestateenhanced.com';
const REONOMY_PASSWORD = process.env.REONOMY_PASSWORD || '9082166532';
const SEARCH_LOCATION = process.env.REONOMY_LOCATION || 'Eatontown, NJ';
const HEADLESS = process.env.HEADLESS === 'true';  // Set to "true" for headless, remove/empty for visible
const MAX_PROPERTIES = 20;
const DEBUG = process.env.DEBUG === 'true';

// Output files
const OUTPUT_FILE = path.join(__dirname, 'reonomy-leads-v11-playwright.json');
const LOG_FILE = path.join(__dirname, 'reonomy-scraper-v11.log');

function log(message) {
  const timestamp = new Date().toISOString();
  const logMessage = `[${timestamp}] ${message}\n`;
  console.log(message);
  fs.appendFileSync(LOG_FILE, logMessage);
}

function logStep(step, message) {
  log(`${step}: ${message}`);
}

async function screenshot(page, name) {
  try {
    const path = `/tmp/reonomy-v11-${name}-${Date.now()}.png`;
    await page.screenshot({ path, fullPage: true });
    log(`📸 Screenshot saved: ${path}`);
  } catch (e) {
    log(`⚠️  Screenshot failed: ${e.message}`);
  }
}

/**
 * Extract ALL data from Owner tab using Playwright
 */
async function extractOwnerTabData(page) {
  return await page.evaluate(() => {
    const info = {
      propertyId: '',
      propertyAddress: '',
      city: '',
      state: '',
      zip: '',
      squareFootage: '',
      propertyType: '',
      emails: [],
      phones: [],
      ownerNames: [],
      pageTitle: document.title,
      bodyTextSample: ''
    };

    // Extract property ID from URL
    const propIdMatch = window.location.href.match(/property\/([a-f0-9-]+)/);
    if (propIdMatch) {
      info.propertyId = propIdMatch[1];
    }

    // Extract property address from h1, h2, h3
    const headingSelectors = ['h1', 'h2', 'h3'];
    for (const sel of headingSelectors) {
      const heading = document.querySelector(sel);
      if (heading) {
        const text = heading.textContent.trim();
        const addressMatch = text.match(/^(\d+[^,]+),\s*([A-Za-z\s,]+),\s*([A-Z]{2})\s*(\d{5})/);
        if (addressMatch) {
          info.propertyAddress = addressMatch[0];
          info.city = addressMatch[1]?.trim();
          info.state = addressMatch[2]?.trim();
          info.zip = addressMatch[3]?.trim();
          break;
        }
      }
    }

    // Extract property details (SF, type)
    const bodyText = document.body.innerText;
    
    // Square footage
    const sfMatch = bodyText.match(/(\d+\.?\d*\s*k?\s*SF)/i);
    if (sfMatch) {
      info.squareFootage = sfMatch[0];
    }

    // Property type
    const typePatterns = ['Warehouse', 'Office Building', 'Retail Stores', 'Industrial', 'General Industrial', 'Medical Building', 'School', 'Religious', 'Supermarket', 'Financial Building'];
    for (const type of typePatterns) {
      if (bodyText.includes(type)) {
        info.propertyType = type;
        break;
      }
    }

    // Extract emails from mailto: links
    document.querySelectorAll('a[href^="mailto:"]').forEach(a => {
      const email = a.href.replace('mailto:', '');
      if (email && email.length > 5 && !info.emails.includes(email)) {
        info.emails.push(email);
      }
    });

    // Also try email patterns in text
    const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
    const emailMatches = bodyText.match(emailRegex);
    if (emailMatches) {
      emailMatches.forEach(email => {
        if (!info.emails.includes(email)) {
          info.emails.push(email);
        }
      });
    }

    // Extract phones from tel: links
    document.querySelectorAll('a[href^="tel:"]').forEach(a => {
      const phone = a.href.replace('tel:', '');
      if (phone && phone.length >= 10 && !info.phones.includes(phone)) {
        info.phones.push(phone);
      }
    });

    // Also try phone patterns in text
    const phoneRegex = /(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g;
    const phoneMatches = bodyText.match(phoneRegex);
    if (phoneMatches) {
      phoneMatches.forEach(phone => {
        if (!info.phones.includes(phone)) {
          info.phones.push(phone);
        }
      });
    }

    // Extract owner names from Owner tab section
    const ownerPatterns = [
      /Owner:\s*([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)/g,
      /Owns\s+\d+\s+properties?\s*([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)/i
    ];
    
    for (const pattern of ownerPatterns) {
      const matches = bodyText.match(pattern);
      if (matches) {
        matches.forEach(m => {
          const owner = typeof m === 'string' ? m : m[1];
          if (owner && owner.length > 3 && !info.ownerNames.includes(owner)) {
            info.ownerNames.push(owner);
          }
        });
      }
    }

    // Save sample for debugging
    info.bodyTextSample = bodyText.substring(0, 500);

    return info;
  });
}

/**
 * Extract property IDs from search results
 */
async function extractPropertyIds(page) {
  return await page.evaluate(() => {
    const ids = [];
    const links = document.querySelectorAll('a[href*="/property/"]');

    links.forEach(link => {
      const href = link.href;
      const match = href.match(/property\/([a-f0-9-]+)/);

      if (match) {
        ids.push({
          id: match[1],
          url: href
        });
      }
    });

    return ids;
  });
}

/**
 * Check if contact details are present (emails or phones)
 */
async function hasContactDetails(page) {
  const data = await extractOwnerTabData(page);
  return data.emails.length > 0 || data.phones.length > 0;
}

/**
 * Apply phone and email filters in advanced search > owner
 * Uses Playwright's robust selectors
 */
async function applyContactFilters(page) {
  log('📍 Step 3b: Applying phone and email filters...');

  // Try to find and click advanced search button using multiple strategies
  const advancedClicked = await page.getByRole('button', { name: /advanced/i }).click().catch(async () => {
    return await page.locator('button').filter({ hasText: /advanced/i }).first().click().catch(async () => {
      return await page.locator('[title*="Advanced" i]').first().click().catch(() => {
        log('  ⚠️  Could not find advanced search button');
        return false;
      });
    });
  });

  if (advancedClicked === false) {
    log('  ⚠️  Continuing without filters');
    return false;
  }

  log('  ✅ Advanced search opened');

  // Wait for filter panel to appear
  await page.waitForTimeout(2000);

  // Click on Owner tab
  const ownerTabClicked = await page.getByRole('tab', { name: /owner/i }).click().catch(async () => {
    return await page.locator('[role="tab"]').filter({ hasText: /owner/i }).first().click().catch(() => {
      log('  ⚠️  Could not find Owner tab');
      return false;
    });
  });

  if (ownerTabClicked !== false) {
    log('  ✅ Owner tab selected');
    await page.waitForTimeout(1000);
  }

  // Enable phone filter
  const phoneFilterEnabled = await page.locator('label').filter({ hasText: /phone/i }).locator('input[type="checkbox"]').first().check().catch(async () => {
    // Try clicking the label itself
    return await page.locator('label').filter({ hasText: /phone.*available/i }).first().click().catch(() => {
      log('  ⚠️  Could not enable phone filter');
      return false;
    });
  });

  if (phoneFilterEnabled !== false) {
    log('  ✅ Phone filter enabled');
  }

  // Enable email filter
  const emailFilterEnabled = await page.locator('label').filter({ hasText: /email/i }).locator('input[type="checkbox"]').first().check().catch(async () => {
    return await page.locator('label').filter({ hasText: /email.*available/i }).first().click().catch(() => {
      log('  ⚠️  Could not enable email filter');
      return false;
    });
  });

  if (emailFilterEnabled !== false) {
    log('  ✅ Email filter enabled');
  }

  // Apply filters - look for Apply, Search, or Done button
  const applyClicked = await page.getByRole('button', { name: /apply|search|done/i }).click().catch(async () => {
    return await page.locator('button').filter({ hasText: /apply|search|done/i }).first().click().catch(() => {
      log('  ⚠️  Could not click apply button');
      return false;
    });
  });

  if (applyClicked !== false) {
    log('  ✅ Filters applied');
    await page.waitForTimeout(3000);
  }

  return phoneFilterEnabled !== false || emailFilterEnabled !== false;
}

/**
 * Wait for contact details using Playwright's waitForFunction
 * Much more efficient than polling with sleep()
 */
async function waitForContactDetails(page, timeoutMs = 30000) {
  log(`  ⏳ Waiting for contact details (up to ${timeoutMs/1000}s)...`);

  try {
    await page.waitForFunction(
      () => {
        const emails = document.querySelectorAll('a[href^="mailto:"]');
        const phones = document.querySelectorAll('a[href^="tel:"]');
        // Also check for email patterns in text
        const emailRegex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
        const bodyText = document.body.innerText;
        const emailMatches = bodyText.match(emailRegex);
        
        return emails.length > 0 || phones.length > 0 || (emailMatches && emailMatches.length > 0);
      },
      { timeout: timeoutMs }
    );

    const data = await extractOwnerTabData(page);
    log(`  ✅ Contact details found! (${data.emails.length} emails, ${data.phones.length} phones)`);
    return true;

  } catch (error) {
    // Timeout is expected if no contacts found
    log('  ⚠️  No contact details found after timeout');
    return false;
  }
}

/**
 * Main scraper using Playwright
 */
async function scrapeLeads() {
  log('🚀 Starting Reonomy Scraper v11 (PLAYWRIGHT)...\n');

  // Launch browser
  const browser = await chromium.launch({
    headless: HEADLESS,
    args: ['--no-sandbox', '--disable-setuid-sandbox']
  });

  const context = await browser.newContext({
    viewport: { width: 1920, height: 1080 }
  });

  const page = await context.newPage();

  const leads = [];

  try {
    // Login
    log('📍 Step 1: Logging into Reonomy...');
    await page.goto('https://app.reonomy.com/#!/account', {
      waitUntil: 'domcontentloaded',
      timeout: 60000
    });

    // Wait for email input
    await page.waitForSelector('input[type="email"]', { timeout: 10000 });
    await page.fill('input[type="email"]', REONOMY_EMAIL);
    await page.fill('input[type="password"]', REONOMY_PASSWORD);
    await page.click('button[type="submit"]');

    log('⏳ Waiting for login...');
    await page.waitForTimeout(10000);

    // Check if logged in
    const url = page.url();
    if (url.includes('login') || url.includes('auth')) {
      throw new Error('Login failed. Please check credentials.');
    }

    log('✅ Successfully logged in!');

    // Navigate to search
    log('\n📍 Step 2: Navigating to search...');
    await page.goto('https://app.reonomy.com/#!/search', {
      waitUntil: 'networkidle',
      timeout: 60000
    });

    // Perform initial search
    log(`📍 Step 3: Searching for: ${SEARCH_LOCATION}...`);

    // Find and fill search input
    const searchInput = page.locator('input[placeholder*="address"], input[placeholder*="Search"], input[type="text"]').first();
    await searchInput.waitFor({ state: 'visible', timeout: 10000 });
    await searchInput.fill(SEARCH_LOCATION);
    await page.keyboard.press('Enter');

    log('⏳ Searching...');
    await page.waitForTimeout(5000);

    // Debug: screenshot before applying filters
    if (DEBUG) await screenshot(page, 'before-filters');

    // Apply phone and email filters
    await applyContactFilters(page);

    // Debug: screenshot after applying filters
    if (DEBUG) await screenshot(page, 'after-filters');

    // Extract search ID from URL
    const urlMatch = page.url().match(/search\/([a-f0-9-]+)/);
    if (!urlMatch) {
      throw new Error('Could not extract search ID from URL');
    }
    const searchId = urlMatch[1];
    log(`✅ Search ID: ${searchId}`);

    // Extract property IDs
    log('\n📍 Step 4: Extracting property IDs...');
    const propertyIds = await extractPropertyIds(page);
    log(`✅ Found ${propertyIds.length} property IDs`);

    if (propertyIds.length === 0) {
      log('⚠️  No property IDs found.');
      throw new Error('No properties found on search page.');
    }

    // Process each property
    const propertiesToScrape = propertyIds.slice(0, MAX_PROPERTIES);

    log(`\n📍 Step 5: Processing ${propertiesToScrape.length} properties...`);

    for (let i = 0; i < propertiesToScrape.length; i++) {
      const prop = propertiesToScrape[i];

      log(`\n[${i + 1}/${propertiesToScrape.length}] Property ID: ${prop.id}`);
      
      // Click on property using Playwright's locator
      log(`  🔗 Clicking property...`);
      
      const clicked = await page.locator('button').filter({ has: page.locator(`a[href*="${prop.id}"]`) }).first().click().catch(async () => {
        // Fallback: navigate directly
        await page.goto(prop.url, { waitUntil: 'networkidle', timeout: 30000 });
        return true;
      });

      if (clicked !== true) {
        log(`  ⚠️  Could not click property, trying to navigate directly...`);
        await page.goto(prop.url, { waitUntil: 'networkidle', timeout: 30000 });
      }

      // Wait for page to load - no arbitrary sleep, use waitForSelector
      log(`  ⏳ Waiting for Owner tab to load...`);
      
      // Wait for any heading or content to appear
      await page.waitForSelector('h1, h2, h3, [role="heading"]', { timeout: 15000 }).catch(() => {
        log('  ⚠️  No heading found, continuing anyway');
      });

      // Smart wait for contact details using Playwright's waitForFunction
      await waitForContactDetails(page, 30000);

      // Extract data from Owner tab
      log(`  📊 Extracting data from Owner tab...`);
      const propertyData = await extractOwnerTabData(page);
      
      log(`  📧 Emails: ${propertyData.emails.length} found`);
      log(`  📞 Phones: ${propertyData.phones.length} found`);
      log(`  👤 Owners: ${propertyData.ownerNames.length} found`);
      log(`  🏢 Address: ${propertyData.propertyAddress || 'N/A'}`);

      const lead = {
        scrapeDate: new Date().toISOString().split('T')[0],
        propertyId: propertyData.propertyId,
        propertyUrl: page.url(),
        address: propertyData.propertyAddress || '',
        city: propertyData.city || '',
        state: propertyData.state || '',
        zip: propertyData.zip || '',
        squareFootage: propertyData.squareFootage || '',
        propertyType: propertyData.propertyType || '',
        ownerNames: propertyData.ownerNames.join('; ') || '',
        emails: propertyData.emails,
        phones: propertyData.phones,
        searchLocation: SEARCH_LOCATION,
        searchId: searchId,
        filtersApplied: { phone: true, email: true }
      };

      leads.push(lead);

      // Go back to search results for next property
      log(`  🔙 Going back to search results...`);
      await page.goto(`https://app.reonomy.com/#!/search/${searchId}`, {
        waitUntil: 'networkidle',
        timeout: 30000
      });

      await page.waitForTimeout(2000);
    }

    // Save results
    if (leads.length > 0) {
      log(`\n✅ Total leads scraped: ${leads.length}`);

      const outputData = {
        scrapeDate: new Date().toISOString(),
        location: SEARCH_LOCATION,
        searchId: searchId,
        leadCount: leads.length,
        filters: { phone: true, email: true },
        framework: 'Playwright',
        leads: leads
      };

      fs.writeFileSync(OUTPUT_FILE, JSON.stringify(outputData, null, 2));
      log(`💾 Saved to: ${OUTPUT_FILE}`);
    } else {
      log('\n⚠️  No leads scraped.');
    }

    log('\n✅ Scraping complete!');

    return { leadCount: leads.length, outputFile: OUTPUT_FILE };

  } catch (error) {
    log(`\n❌ Error: ${error.message}`);
    log(error.stack);

    try {
      await page.screenshot({ path: '/tmp/reonomy-v11-error.png', fullPage: true });
      log('📸 Error screenshot saved: /tmp/reonomy-v11-error.png');
    } catch (e) {}

    throw error;

  } finally {
    await context.close();
    await browser.close();
    log('\n🔚 Browser closed');
  }
}

// Run
scrapeLeads()
  .then(result => {
    log(`\n🎉 Success! ${result.leadCount} leads scraped.`);
    console.log(`\n💾 View your leads at: ${result.outputFile}`);
    process.exit(0);
  })
  .catch(error => {
    log(`\n💥 Scraper failed: ${error.message}`);
    process.exit(1);
  });
