import puppeteer, { Browser, Page } from 'puppeteer'
import { promises as fs } from 'fs'
import * as path from 'path'

export interface TradingViewCredentials {
  email: string
  password: string
}

// Environment variables fallback
const TRADINGVIEW_EMAIL = process.env.TRADINGVIEW_EMAIL
const TRADINGVIEW_PASSWORD = process.env.TRADINGVIEW_PASSWORD

// Utility function to replace Puppeteer's waitForTimeout
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))

// Helper function to check if element is visible using Puppeteer APIs
async function isElementVisible(page: Page, selector: string, timeout: number = 1000): Promise<boolean> {
  try {
    await page.waitForSelector(selector, { timeout, visible: true })
    return true
  } catch {
    return false
  }
}

export interface NavigationOptions {
  symbol?: string // e.g., 'SOLUSD', 'BTCUSD'
  timeframe?: string // e.g., '5', '15', '1H'
  waitForChart?: boolean
}

// Session persistence configuration
const SESSION_DATA_DIR = path.join(process.cwd(), '.tradingview-session')
const COOKIES_FILE = path.join(SESSION_DATA_DIR, 'cookies.json')
const SESSION_STORAGE_FILE = path.join(SESSION_DATA_DIR, 'session-storage.json')

export class TradingViewAutomation {
  private browser: Browser | null = null
  private page: Page | null = null
  private isAuthenticated: boolean = false
  private static instance: TradingViewAutomation | null = null
  private initPromise: Promise<void> | null = null
  private operationLock: boolean = false
  private lastRequestTime = 0
  private requestCount = 0

  private acquireOperationLock(): void {
    if (this.operationLock) {
      throw new Error('Another operation is already in progress. Please wait.')
    }
    this.operationLock = true
  }

  private releaseOperationLock(): void {
    this.operationLock = false
  }

  // Singleton pattern
  static getInstance(): TradingViewAutomation {
    if (!TradingViewAutomation.instance) {
      TradingViewAutomation.instance = new TradingViewAutomation()
    }
    return TradingViewAutomation.instance
  }

  async init(forceCleanup: boolean = false): Promise<void> {
    this.acquireOperationLock()
    try {
      if (this.initPromise) {
        console.log('🔄 Initialization already in progress, waiting...')
        await this.initPromise
        return
      }

      if (forceCleanup && this.browser) {
        console.log('🧹 Force cleanup requested')
        await this.forceCleanup()
      }

      if (this.browser) {
        console.log('SUCCESS: Browser already initialized and connected')
        return
      }

      this.initPromise = this._doInit()
      try {
        await this.initPromise
      } finally {
        this.initPromise = null
      }
    } finally {
      this.releaseOperationLock()
    }
  }

  private async _doInit(): Promise<void> {
    console.log('🚀 Initializing TradingView automation with session persistence...')
    
    // Ensure session directory exists
    await fs.mkdir(SESSION_DATA_DIR, { recursive: true })
    
    try {
      this.browser = await puppeteer.launch({
        headless: true,
        executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || process.env.CHROME_PATH || '/usr/bin/chromium',
        timeout: 60000,
        args: [
          '--no-sandbox',
          '--disable-setuid-sandbox',
          '--disable-dev-shm-usage',
          '--disable-accelerated-2d-canvas',
          '--no-first-run',
          '--no-zygote',
          '--disable-gpu',
          '--disable-web-security',
          '--disable-features=VizDisplayCompositor',
          '--disable-background-timer-throttling',
          '--disable-backgrounding-occluded-windows',
          '--disable-renderer-backgrounding',
          '--disable-features=TranslateUI',
          '--disable-ipc-flooding-protection',
          '--disable-extensions',
          '--disable-default-apps',
          '--disable-sync',
          '--window-size=1920,1080',
          '--user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
          // Additional flags to prevent zombie processes
          '--disable-background-networking',
          '--disable-background-timer-throttling',
          '--disable-backgrounding-occluded-windows',
          '--disable-breakpad',
          '--disable-client-side-phishing-detection',
          '--disable-component-extensions-with-background-pages',
          '--disable-crash-reporter',
          '--disable-hang-monitor',
          '--disable-prompt-on-repost',
          '--no-crash-upload'
          // Removed --single-process as it causes issues with Puppeteer
        ]
      })

      this.page = await this.browser.newPage()
      
      // Set viewport
      await this.page.setViewport({ width: 1920, height: 1080 })

      // Load saved session if available
      await this.loadSession()

      console.log('✅ Browser initialized successfully')
    } catch (error) {
      console.error('❌ Failed to initialize browser:', error)
      await this.forceCleanup()
      throw error
    }
  }

  async forceCleanup(): Promise<void> {
    console.log('🧹 Force cleanup: Closing browser and resetting state...')
    try {
      if (this.browser) {
        // First, close all pages
        const pages = await this.browser.pages()
        for (const page of pages) {
          try {
            await page.close()
          } catch (e) {
            console.log('WARNING: Error closing page:', e)
          }
        }
        
        // Then close the browser
        await this.browser.close()
        
        // Force kill any remaining processes
        const browserProcess = this.browser.process()
        if (browserProcess && !browserProcess.killed) {
          browserProcess.kill('SIGKILL')
        }
      }
    } catch (e) {
      console.log('WARNING: Error during browser cleanup:', e)
    }
    
    this.browser = null
    this.page = null
    this.isAuthenticated = false
    this.operationLock = false
    console.log('✅ Cleanup completed')
  }

  private async loadSession(): Promise<void> {
    if (!this.page) return
    
    try {
      // Load cookies
      if (await fs.access(COOKIES_FILE).then(() => true).catch(() => false)) {
        const cookiesData = await fs.readFile(COOKIES_FILE, 'utf8')
        const cookies = JSON.parse(cookiesData)
        await this.page.setCookie(...cookies)
        console.log('✅ Loaded saved cookies')
      }
    } catch (e) {
      console.log('WARNING: Could not load session:', e)
    }
  }

  private async saveSession(): Promise<void> {
    if (!this.page) return
    
    try {
      // Save cookies
      const cookies = await this.page.cookies()
      await fs.writeFile(COOKIES_FILE, JSON.stringify(cookies, null, 2))
      console.log('✅ Session saved')
    } catch (e) {
      console.log('WARNING: Could not save session:', e)
    }
  }

  async checkLoginStatus(): Promise<boolean> {
    if (!this.page) return false
    
    try {
      console.log('🔍 CHECKING LOGIN STATUS - Starting comprehensive authentication detection...')
      
      // Strategy 1: Check JavaScript authentication variables
      console.log('CHECKING: Strategy 1: JavaScript authentication variables...')
      const authStatus = await this.page.evaluate(() => {
        console.log('EVAL: Starting JavaScript authentication check...')
        
        // Check window.is_authenticated
        console.log('EVAL: Checking window.is_authenticated...')
        const isAuthVar = (window as any).is_authenticated
        console.log('EVAL: window.is_authenticated =', isAuthVar, typeof isAuthVar)
        
        // Check window.user
        console.log('EVAL: Checking window.user...')
        const userVar = (window as any).user
        console.log('EVAL: window.user =', userVar, typeof userVar)
        
        // Check if user object has meaningful data
        if (userVar && typeof userVar === 'object') {
          console.log('EVAL: User object keys:', Object.keys(userVar))
          console.log('EVAL: User object values preview:', JSON.stringify(userVar).substring(0, 200))
        }
        
        // Return authentication status
        const result = isAuthVar === true || (userVar && typeof userVar === 'object' && Object.keys(userVar).length > 0)
        console.log('EVAL: Final Strategy 1 result:', result)
        return result
      })
      
      console.log('CHECKING: Strategy 1 JavaScript result:', authStatus)
      if (authStatus) {
        console.log('✅ Strategy 1: Authenticated via JavaScript variables')
        return true
      }
      
      // Strategy 1.5: Check for user avatar/profile elements (indicates logged in state)
      console.log('CHECKING: Strategy 1.5: User interface elements...')
      const userElements = await this.page.$$eval('[data-testid="header-user-menu"], .tv-header__user-menu, [class*="user-menu"], [class*="avatar"], [data-name="header-user-menu"]', elements => {
        console.log('EVAL: Found', elements.length, 'potential user elements')
        return elements.length > 0
      }).catch(() => false)
      
      if (userElements) {
        console.log('Strategy 1.5: Found user interface elements - likely authenticated')
        return true
      }
      
      // Strategy 2: Check for absence of login forms (indicates already logged in)
      console.log('CHECKING: Strategy 2: Absence of login forms...')
      const pageUrl = this.page.url()
      console.log('CHECKING: Current URL:', pageUrl)
      
      // If we're not on a login page and no login forms exist, we're likely logged in
      const hasLoginForms = await this.page.$('input[type="email"], input[name="username"], input[name="email"], input[type="password"]').then(el => !!el).catch(() => false)
      const isOnLoginPage = pageUrl.includes('/signin') || pageUrl.includes('/login') || pageUrl.includes('/accounts/signin')
      
      console.log('CHECKING: Has login forms:', hasLoginForms)
      console.log('CHECKING: Is on login page:', isOnLoginPage)
      
      if (!hasLoginForms && !isOnLoginPage) {
        console.log('Strategy 2: No login forms and not on login page - likely authenticated')
        return true
      }
      
      // Strategy 3: Check for "Sign In" vs "User Menu" buttons
      console.log('CHECKING: Strategy 3: Page action buttons...')
      const hasSignInButton = await this.page.$('[data-testid="header-signin-button"], a[href*="signin"], button:has-text("Sign in")').then(el => !!el).catch(() => false)
      const hasUserMenu = await this.page.$('[data-testid="header-user-menu"], .tv-header__user-menu, [class*="user-menu"]').then(el => !!el).catch(() => false)
      
      console.log('CHECKING: Has sign in button:', hasSignInButton)
      console.log('CHECKING: Has user menu:', hasUserMenu)
      
      if (!hasSignInButton && hasUserMenu) {
        console.log('Strategy 3: User menu present, no sign in button - authenticated')
        return true
      }
      
      if (!hasSignInButton && !isOnLoginPage) {
        console.log('Strategy 3: No sign in button and not on login page - likely authenticated')
        return true
      }
      
      // Strategy 2: Check for user account indicators (positive indicators)
      console.log('CHECKING: Strategy 2: Checking for user account indicators...')
      await this.takeDebugScreenshot('login_status_check')
      
      const userIndicators = [
        '.js-header-user-menu-button', // TradingView's main user button
        '[data-name="header-user-menu"]',
        '.tv-header__user-menu-button:not(.tv-header__user-menu-button--anonymous)',
        '.tv-header__user-menu-wrap'
      ]
      
      for (const selector of userIndicators) {
        try {
          const element = await this.page.$(selector)
          if (element) {
            const isVisible = await element.boundingBox()
            if (isVisible) {
              console.log('SUCCESS: Found user account element: ' + selector)
              return true
            }
          }
        } catch (e) {
          continue
        }
      }
      
      // Strategy 3: Check for anonymous/sign-in indicators (negative indicators)
      console.log('CHECKING: Strategy 3: Checking for anonymous/sign-in indicators...')
      const anonymousIndicators = [
        '.tv-header__user-menu-button--anonymous',
        '[data-name="header-user-menu-sign-in"]',
        'button:contains("Sign in")',
        'a:contains("Sign in")'
      ]
      
      for (const selector of anonymousIndicators) {
        try {
          const element = await this.page.$(selector)
          if (element) {
            const isVisible = await element.boundingBox()
            if (isVisible) {
              console.log('ERROR: Found anonymous indicator: ' + selector + ' - not logged in')
              return false
            }
          }
        } catch (e) {
          continue
        }
      }
      
      // Strategy 4: Check URL patterns
      console.log('CHECKING: Strategy 4: Checking URL patterns...')
      const urlCheck = this.page.url()
      if (urlCheck.includes('/signin') || urlCheck.includes('/login')) {
        console.log('ERROR: On login page - not logged in')
        return false
      }
      
      // Strategy 5: Check authentication cookies
      console.log('CHECKING: Strategy 5: Checking authentication cookies...')
      const cookies = await this.page.cookies()
      const authCookies = cookies.filter(cookie => 
        cookie.name.includes('auth') || 
        cookie.name.includes('session') ||
        cookie.name.includes('token')
      )
      if (authCookies.length === 0) {
        console.log('WARNING: No authentication cookies found')
      }
      
      // Strategy 6: Check for personal content
      console.log('CHECKING: Strategy 6: Checking for personal content...')
      const personalContentSelectors = [
        '[data-name="watchlist"]',
        '.tv-header__watchlist',
        '.js-backtesting-head'
      ]
      
      for (const selector of personalContentSelectors) {
        try {
          const element = await this.page.$(selector)
          if (element) {
            console.log('SUCCESS: Found personal content: ' + selector)
            return true
          }
        } catch (e) {
          continue
        }
      }
      
      // Strategy 7: Check for absence of login interface (final check)
      console.log('CHECKING: Strategy 7: Final absence of login interface check...')
      const finalUrlCheck = this.page.url()
      const hasAnyLoginElements = await this.page.$('input[type="email"], input[name="username"], input[name="email"], input[type="password"], [href*="signin"], [href*="login"], button:has-text("Sign in")').then(el => !!el).catch(() => false)
      const isOnMainTradingViewDomain = finalUrlCheck.includes('tradingview.com') && !finalUrlCheck.includes('/signin') && !finalUrlCheck.includes('/login')
      
      console.log('CHECKING: Has any login elements:', hasAnyLoginElements)
      console.log('CHECKING: Is on main TradingView domain (not login page):', isOnMainTradingViewDomain)
      
      if (isOnMainTradingViewDomain && !hasAnyLoginElements) {
        console.log('✅ Strategy 7: On main TradingView domain with no login elements - authenticated')
        return true
      }
      
      // If we can't determine status clearly, assume not logged in to be safe
      console.log('WARNING: Could not determine login status clearly, assuming not logged in')
      return false
      
    } catch (e) {
      console.log('ERROR: Error checking login status:', e)
      return false
    }
  }

  async login(credentials?: TradingViewCredentials): Promise<boolean> {
    if (!this.page) throw new Error('Page not initialized')

    const email = credentials?.email || TRADINGVIEW_EMAIL
    const password = credentials?.password || TRADINGVIEW_PASSWORD

    if (!email || !password) {
      throw new Error('TradingView credentials not provided')
    }

    try {
      // Check if already logged in
      const loggedIn = await this.checkLoginStatus()
      if (loggedIn) {
        console.log('SUCCESS: Already logged in, skipping login steps')
        return true
      }

      console.log('🔐 Starting login process...')
      
      // Navigate to main TradingView page first, then find login
      console.log('📄 Navigating to TradingView main page...')
      
      try {
        await this.page.goto('https://www.tradingview.com/', {
          waitUntil: 'domcontentloaded',
          timeout: 30000
        })
        
        await sleep(3000)
        
        // Look for sign in buttons on main page
        console.log('🔍 Looking for Sign In button on main page...')
        const signinButtons = [
          'a[href*="signin"]',
          'a[href*="accounts/signin"]',
          '[data-name="header-user-menu-sign-in"]',
          '.tv-header__user-menu-button',
          '.tv-header__user-menu-button--anonymous',
          '.js-signin-switch',
          'button[data-role="button"]',
          'button.tv-button',
          'a.tv-button'
        ]
        
        let foundSignin = false
        for (const selector of signinButtons) {
          try {
            const elements = await this.page.$$(selector)
            
            for (const element of elements) {
              const isVisible = await element.boundingBox()
              if (isVisible) {
                const text = await element.evaluate(el => {
                  const elem = el as HTMLElement
                  return elem.textContent || elem.getAttribute('title') || elem.getAttribute('href') || ''
                })
                  console.log(`Found signin element: ${selector} with text: "${text}"`)                // Check if this looks like a sign in button
                const lowerText = text.toLowerCase()
                if (lowerText.includes('sign in') || lowerText.includes('login') || 
                    lowerText.includes('signin') || selector.includes('signin') ||
                    selector.includes('user-menu-button')) {
                  
                  await element.click()
                  console.log('✅ Clicked sign in button')
                  await sleep(5000) // Wait for login page/modal to load
                  foundSignin = true
                  break
                }
              }
            }
            if (foundSignin) break
          } catch (e) {
            const error = e as Error
            console.log(`❌ Error with selector ${selector}: ${error.message}`)
            continue
          }
        }
        
        // If no selector-based approach works, try finding by text content
        if (!foundSignin) {
          console.log('🔍 Trying to find sign-in button by text content...')
          const clickableElements = await this.page.$$('button, a, div[role="button"], span[role="button"]')
          
          for (const element of clickableElements) {
            try {
              const isVisible = await element.boundingBox()
              if (isVisible) {
                const text = await element.evaluate(el => {
                  const elem = el as HTMLElement
                  return (elem.textContent || '').toLowerCase().trim()
                })
                
                if (text.includes('sign in') || text.includes('signin') || text.includes('log in') || text.includes('login')) {
                  console.log(`🎯 Found sign-in button with text: "${text}"`)
                  await element.click()
                  console.log('✅ Clicked sign-in button by text')
                  await sleep(5000)
                  foundSignin = true
                  break
                }
              }
            } catch (e) {
              continue
            }
          }
        }
        
        if (!foundSignin) {
          console.log('⚠️  No sign in button found on main page, trying direct navigation...')
          await this.page.goto('https://www.tradingview.com/accounts/signin/', {
            waitUntil: 'domcontentloaded',
            timeout: 30000
          })
        }
        
      } catch (e) {
        const error = e as Error
        console.log(`❌ Navigation error: ${error.message}`)
        // Fallback to direct login URL
        await this.page.goto('https://www.tradingview.com/accounts/signin/', {
          waitUntil: 'domcontentloaded',
          timeout: 30000
        })
      }
      
      await sleep(3000)
      await this.takeDebugScreenshot('login_page_loaded')
      
      // Check current URL and page state
      const currentUrl = await this.page.url()
      const pageTitle = await this.page.title()
      console.log(`🌐 Current URL: ${currentUrl}`)
      console.log(`📋 Page title: ${pageTitle}`)

      // Wait for login form
      console.log('⏳ Waiting for login form...')
      await sleep(5000)

      // Look for email login option with comprehensive approach
      console.log('CHECKING: Looking for Email login option...')
      
      // Try to find email trigger button using XPath and text content
      let emailFormVisible = false
      
      try {
        // First try standard selectors
        const emailTriggers = [
          'button[data-overflow-tooltip-text="Email"]',
          '[data-name="email"]',
          '.tv-signin-dialog__toggle-email',
          '.js-signin__email',
          '[data-testid="email-signin"]',
          'button[class*="email"]',
          '.signin-form__toggle'
        ]
        
        for (const trigger of emailTriggers) {
          try {
            const elements = await this.page.$$(trigger)
            for (const element of elements) {
              const isVisible = await element.boundingBox()
              if (isVisible) {
                const text = await element.evaluate(el => {
                  const elem = el as HTMLElement
                  return elem.textContent || elem.getAttribute('data-overflow-tooltip-text') || elem.getAttribute('title') || ''
                })
                console.log(`TARGET: Found email trigger: ${trigger} with text: "${text}"`)
                await element.click()
                console.log('SUCCESS: Clicked email trigger')
                await sleep(3000)
                emailFormVisible = true
                break
              }
            }
            if (emailFormVisible) break
          } catch (e) {
            continue
          }
        }
        
        // If no standard selectors work, try finding buttons by text content
        if (!emailFormVisible) {
          console.log('🔍 Trying to find email button by text content...')
          const buttons = await this.page.$$('button, span, div[role="button"], a')
          
          for (const button of buttons) {
            try {
              const isVisible = await button.boundingBox()
              if (isVisible) {
                const text = await button.evaluate(el => {
                  const elem = el as HTMLElement
                  return (elem.textContent || '').toLowerCase().trim()
                })
                
                if (text.includes('email') || text.includes('continue with email')) {
                  console.log(`🎯 Found email button with text: "${text}"`)
                  await button.click()
                  console.log('✅ Clicked email button by text')
                  await sleep(3000)
                  emailFormVisible = true
                  break
                }
              }
            } catch (e) {
              continue
            }
          }
        }
        
      } catch (e) {
        console.log('⚠️ Error finding email trigger:', e)
      }
      
      // If no email trigger found, check if we're in a modal or different login flow
      if (!emailFormVisible) {
        console.log('INFO: No email trigger found, checking for alternative login flows...')
        
        // Wait a bit more for any modals to fully load
        await sleep(5000)
        await this.takeDebugScreenshot('checking_modal_login')
        
        // Check for modal dialogs or different login containers
        const modalSelectors = [
          '[role="dialog"]',
          '.tv-dialog',
          '.tv-dialog__wrapper',
          '.js-dialog',
          '.signin-dialog',
          '.auth-modal',
          '.modal',
          '[data-testid="auth-modal"]'
        ]
        
        for (const modalSelector of modalSelectors) {
          try {
            const modal = await this.page.$(modalSelector)
            if (modal) {
              console.log(`📋 Found modal: ${modalSelector}`)
              // Look for email options within the modal
              const modalEmailButtons = await modal.$$('button, a, div[role="button"]')
              
              for (const button of modalEmailButtons) {
                try {
                  const isVisible = await button.boundingBox()
                  if (isVisible) {
                    const text = await button.evaluate(el => {
                      const elem = el as HTMLElement
                      return (elem.textContent || '').toLowerCase().trim()
                    })
                    
                    console.log(`🎯 Modal button text: "${text}"`)
                    if (text.includes('email') || text.includes('continue with email') || 
                        text.includes('sign in with email') || text.includes('use email')) {
                      console.log(`✅ Found modal email button: "${text}"`)
                      await button.click()
                      console.log('✅ Clicked modal email button')
                      await sleep(3000)
                      emailFormVisible = true
                      break
                    }
                  }
                } catch (e) {
                  continue
                }
              }
              if (emailFormVisible) break
            }
          } catch (e) {
            continue
          }
        }
      }
      
      if (!emailFormVisible) {
        console.log('INFO: Still no email form, assuming email form is already visible')
      }
      
      await this.takeDebugScreenshot('after_email_trigger')

      // Fill email - updated selectors for current TradingView
      const emailInputSelectors = [
        'input[type="email"]',
        'input[name*="email"]', 
        'input[name="username"]',
        'input[name="id_username"]',
        'input[placeholder*="email" i]',
        'input[placeholder*="Email" i]',
        'input[autocomplete="username"]',
        'input[data-name="email"]',
        'input[class*="email"]',
        '#id_username',
        '#email',
        '[data-testid="email-input"]',
        '[data-testid="username-input"]'
      ]
      
      // Debug: Check what's actually on the page
      await this.takeDebugScreenshot('before_email_search')
      
      // Get all input elements to debug
      const allInputs = await this.page.$$('input')
      console.log(`DEBUG: Found ${allInputs.length} input elements on page`)
      
      for (let i = 0; i < Math.min(allInputs.length, 10); i++) {
        try {
          const inputType = await allInputs[i].evaluate(el => el.type)
          const inputName = await allInputs[i].evaluate(el => el.name)
          const inputPlaceholder = await allInputs[i].evaluate(el => el.placeholder)
          const inputId = await allInputs[i].evaluate(el => el.id)
          const inputClass = await allInputs[i].evaluate(el => el.className)
          const inputValue = await allInputs[i].evaluate(el => el.value)
          const isVisible = await allInputs[i].boundingBox()
          
          console.log(`INPUT ${i}: type="${inputType}", name="${inputName}", placeholder="${inputPlaceholder}", id="${inputId}", class="${inputClass}", value="${inputValue}", visible=${!!isVisible}`)
          
          // Check if this looks like an email/username field even if it doesn't match selectors
          if (isVisible && (inputType === 'text' || inputType === 'email' || !inputType)) {
            const lowerPlaceholder = (inputPlaceholder || '').toLowerCase()
            const lowerName = (inputName || '').toLowerCase()
            const lowerClass = (inputClass || '').toLowerCase()
            
            if (lowerPlaceholder.includes('email') || lowerPlaceholder.includes('username') ||
                lowerName.includes('email') || lowerName.includes('username') ||
                lowerClass.includes('email') || lowerClass.includes('username')) {
              console.log(`🎯 INPUT ${i} looks like email field based on attributes`)
            }
          }
        } catch (e) {
          const error = e as Error
          console.log(`INPUT ${i}: Error reading attributes - ${error.message}`)
        }
      }
      
      let emailInput = null
      
      // First try specific selectors
      for (const selector of emailInputSelectors) {
        try {
          emailInput = await this.page.$(selector)
          if (emailInput) {
            const isVisible = await emailInput.boundingBox()
            if (isVisible) {
              console.log('SUCCESS: Found email input: ' + selector)
              break
            }
          }
        } catch (e) {
          continue
        }
        emailInput = null // Reset if not visible
      }
      
      // If no specific selector worked, try to find the first visible text input
      if (!emailInput) {
        console.log('🔍 No specific email input found, trying first visible text input...')
        for (const input of allInputs) {
          try {
            const isVisible = await input.boundingBox()
            const inputType = await input.evaluate(el => el.type)
            
            if (isVisible && (inputType === 'text' || inputType === 'email' || !inputType)) {
              console.log('🎯 Found first visible text input, assuming it\'s email field')
              emailInput = input
              break
            }
          } catch (e) {
            continue
          }
        }
      }
      
      // Last resort: try to find inputs by looking for labels or surrounding text
      if (!emailInput) {
        console.log('🔍 Last resort: searching for inputs near email-related text...')
        
        // Look for text that says "email" and find nearby inputs
        const emailTexts = await this.page.evaluate(() => {
          const allElements = Array.from(document.querySelectorAll('*'))
          return allElements
            .filter(el => {
              const text = (el.textContent || '').toLowerCase()
              return text.includes('email') || text.includes('username') || text.includes('sign in')
            })
            .map(el => {
              const rect = el.getBoundingClientRect()
              return {
                text: (el.textContent || '').trim(),
                x: rect.x,
                y: rect.y,
                tag: el.tagName
              }
            })
        })
        
        console.log('📋 Found email-related text elements:', emailTexts.slice(0, 5))
        
        // Try to find any input that's not already found
        for (const input of allInputs) {
          try {
            const isVisible = await input.boundingBox()
            if (isVisible) {
              console.log('🎯 Using any visible input as potential email field')
              emailInput = input
              break
            }
          } catch (e) {
            continue
          }
        }
      }
      
      if (!emailInput) {
        // Additional debug info
        const currentUrl = await this.page.url()
        const title = await this.page.title()
        console.log(`❌ Email input not found on: ${currentUrl}`)
        console.log(`❌ Page title: ${title}`)
        await this.takeDebugScreenshot('email_input_not_found')
        throw new Error(`Could not find email input field on ${currentUrl}. Found ${allInputs.length} inputs total.`)
      }
      
      await emailInput.click()
      await emailInput.type(email)
      console.log('✅ Filled email field')

      // Fill password
      const passwordInputSelectors = [
        'input[type="password"]',
        'input[name*="password"]'
      ]
      
      let passwordInput = null
      for (const selector of passwordInputSelectors) {
        try {
          passwordInput = await this.page.$(selector)
          if (passwordInput) {
            const isVisible = await passwordInput.boundingBox()
            if (isVisible) {
              console.log('SUCCESS: Found password input: ' + selector)
              break
            }
          }
        } catch (e) {
          continue
        }
      }
      
      if (!passwordInput) {
        throw new Error('Could not find password input field')
      }
      
      await passwordInput.click()
      await passwordInput.type(password)
      console.log('✅ Filled password field')

      // Submit form
      const submitSelectors = [
        'button[type="submit"]',
        'button:contains("Sign in")',
        'button:contains("Log in")',
        'button:contains("Login")'
      ]
      
      let submitted = false
      for (const selector of submitSelectors) {
        try {
          const button = await this.page.$(selector)
          if (button) {
            const isVisible = await button.boundingBox()
            if (isVisible) {
              console.log('SUCCESS: Found submit button: ' + selector)
              await button.click()
              submitted = true
              break
            }
          }
        } catch (e) {
          continue
        }
      }
      
      if (!submitted) {
        // Try pressing Enter on password field
        await passwordInput.press('Enter')
        console.log('INFO: Pressed Enter on password field')
      }

      console.log('⏳ Waiting for login completion...')
      await sleep(5000)

      // Check for errors
      const errorSelectors = [
        '.tv-alert-dialog__text',
        '.tv-dialog__error',
        '[data-name="auth-error-message"]',
        '.error-message'
      ]
      
      for (const selector of errorSelectors) {
        try {
          const errorElement = await this.page.$(selector)
          if (errorElement) {
            const errorText = await this.page.evaluate(el => el.textContent, errorElement)
            if (errorText && errorText.trim()) {
              await this.takeDebugScreenshot('login_error')
              throw new Error('Login failed: ' + errorText.trim())
            }
          }
        } catch (e) {
          continue
        }
      }

      // Verify login success
      await sleep(3000)
      const loginSuccess = await this.checkLoginStatus()
      
      if (loginSuccess) {
        console.log('✅ Login successful!')
        this.isAuthenticated = true
        await this.saveSession()
        return true
      } else {
        await this.takeDebugScreenshot('login_verification_failed')
        throw new Error('Login verification failed - still appears not logged in')
      }

    } catch (error) {
      console.error('❌ Login failed:', error)
      await this.takeDebugScreenshot('login_error')
      throw error
    }
  }

  async takeDebugScreenshot(prefix: string = 'debug'): Promise<string> {
    if (!this.page) throw new Error('Page not initialized')
    
    try {
      const timestamp = Date.now()
      const filename = `${prefix}_${timestamp}.png`
      const filepath = path.join(process.cwd(), 'screenshots', filename)
      
      // Ensure screenshots directory exists
      await fs.mkdir(path.dirname(filepath), { recursive: true })
      
      await this.page.screenshot({ 
        path: filepath as `${string}.png`, 
        fullPage: true,
        type: 'png'
      })
      
      console.log(`📸 Screenshot saved: ${filename}`)
      return filepath
    } catch (error) {
      console.error('Error taking screenshot:', error)
      throw error
    }
  }

  async navigateToLayout(layoutId: string, symbol: string, timeframe?: string): Promise<boolean> {
    if (!this.page) throw new Error('Page not initialized')
    
    try {
      console.log(`🎯 Navigating to layout ${layoutId} with symbol: ${symbol}`)
      
      // Construct direct layout URL - this bypasses the generic chart URL issue
      const directUrl = `https://www.tradingview.com/chart/${layoutId}/?symbol=${symbol}${timeframe ? `&interval=${timeframe}` : ''}`
      console.log(`📍 Direct layout navigation to: ${directUrl}`)
      
      await this.page.goto(directUrl, {
        waitUntil: 'domcontentloaded',
        timeout: 30000
      })
      
      // Wait for chart to load
      await sleep(5000)
      
      // Wait for chart container
      await this.page.waitForSelector('.chart-container, #chart-container, [data-name="chart"]', {
        timeout: 30000
      })
      
      console.log(`✅ Successfully navigated to layout ${layoutId}`)
      return true
      
    } catch (error) {
      console.error(`❌ Failed to navigate to layout ${layoutId}:`, error)
      return false
    }
  }

  async navigateToSymbol(symbol: string, timeframe?: string): Promise<boolean> {
    if (!this.page) throw new Error('Page not initialized')
    
    try {
      console.log(`🎯 Navigating to symbol: ${symbol}`)
      
      // Construct TradingView URL
      const baseUrl = 'https://www.tradingview.com/chart/'
      const params = new URLSearchParams()
      params.set('symbol', symbol)
      if (timeframe) {
        params.set('interval', timeframe)
      }
      
      const url = `${baseUrl}?${params.toString()}`
      console.log(`📍 Navigating to: ${url}`)
      
      await this.page.goto(url, {
        waitUntil: 'domcontentloaded',
        timeout: 30000
      })
      
      // Wait for chart to load
      await sleep(5000)
      
      // Wait for chart container
      await this.page.waitForSelector('.chart-container, #chart-container, [data-name="chart"]', {
        timeout: 30000
      })
      
      console.log('✅ Chart loaded successfully')
      return true
      
    } catch (error) {
      console.error('❌ Failed to navigate to symbol:', error)
      throw error
    }
  }

  async takeScreenshot(options: { filename?: string, fullPage?: boolean } = {}): Promise<string> {
    if (!this.page) throw new Error('Page not initialized')
    
    try {
      const timestamp = Date.now()
      const filename = options.filename || `screenshot_${timestamp}.png`
      const filepath = path.join(process.cwd(), 'screenshots', filename)
      
      // Ensure screenshots directory exists
      await fs.mkdir(path.dirname(filepath), { recursive: true })
      
      await this.page.screenshot({ 
        path: filepath as `${string}.png`, 
        fullPage: options.fullPage || false,
        type: 'png'
      })
      
      console.log(`📸 Screenshot saved: ${filename}`)
      return filepath
    } catch (error) {
      console.error('Error taking screenshot:', error)
      throw error
    }
  }
}

// Export default instance
export const tradingViewAutomation = TradingViewAutomation.getInstance()
export default TradingViewAutomation.getInstance()
