import puppeteer, { Browser, Page, Frame } from 'puppeteer'
import path from 'path'
import fs from 'fs/promises'
import { settingsManager } from './settings'

const TRADINGVIEW_EMAIL = process.env.TRADINGVIEW_EMAIL
const TRADINGVIEW_PASSWORD = process.env.TRADINGVIEW_PASSWORD
const TRADINGVIEW_LAYOUTS = (process.env.TRADINGVIEW_LAYOUTS || '').split(',').map(l => l.trim())
const PUPPETEER_EXECUTABLE_PATH = process.env.PUPPETEER_EXECUTABLE_PATH || '/usr/bin/chromium'

// Layout name to URL mapping
const LAYOUT_URLS: { [key: string]: string } = {
  'ai': 'Z1TzpUrf',
  'Diy module': 'vWVvjLhP',
  // Add more layout mappings as needed
}

export class TradingViewCapture {
  private browser: Browser | null = null
  private page: Page | null = null
  private loggedIn = false

  async init() {
    if (!this.browser) {
      this.browser = await puppeteer.launch({
        headless: true,
        args: [
          '--no-sandbox',
          '--disable-setuid-sandbox',
          '--disable-dev-shm-usage',
          '--disable-accelerated-2d-canvas',
          '--no-first-run',
          '--no-zygote',
          '--disable-gpu'
        ],
        executablePath: PUPPETEER_EXECUTABLE_PATH
      })
      console.log('Puppeteer browser launched')
    }
    if (!this.page) {
      this.page = await this.browser.newPage()
      await this.page.setViewport({ width: 1920, height: 1080 })
      console.log('Puppeteer page created')
    }
    if (!this.loggedIn) {
      console.log('Logging in to TradingView...')
      await this.login()
      this.loggedIn = true
      console.log('Logged in to TradingView')
    }
    return this.page
  }

  async login() {
    if (!TRADINGVIEW_EMAIL || !TRADINGVIEW_PASSWORD) {
      throw new Error('TradingView credentials not set in .env')
    }
    const page = this.page || (await this.browser!.newPage())
    console.log('Navigating to TradingView login page...')
    await page.goto('https://www.tradingview.com/#signin', { waitUntil: 'networkidle2' })
    
    // Check if we're already logged in
    try {
      const loggedInIndicator = await page.waitForSelector('.tv-header__user-menu-button, [data-name="header-user-menu"]', { timeout: 3000 })
      if (loggedInIndicator) {
        console.log('Already logged in to TradingView')
        return
      }
    } catch (e) {
      console.log('Not logged in yet, proceeding with login...')
    }
    
    try {
      // Wait for the login modal to appear and look for email input directly
      console.log('Looking for email input field...')
      
      // Try to find the email input field directly (new TradingView layout)
      const emailInput = await page.waitForSelector('input[name="username"], input[name="email"], input[type="email"], input[placeholder*="email" i]', { timeout: 10000 })
      
      if (emailInput) {
        console.log('Found email input field directly')
        await emailInput.click() // Click to focus
        await emailInput.type(TRADINGVIEW_EMAIL, { delay: 50 })
        
        // Find password field
        const passwordInput = await page.waitForSelector('input[name="password"], input[type="password"], input[placeholder*="password" i]', { timeout: 5000 })
        if (!passwordInput) {
          throw new Error('Could not find password input field')
        }
        await passwordInput.click() // Click to focus
        await passwordInput.type(TRADINGVIEW_PASSWORD, { delay: 50 })
        
        // Find and click the sign in button
        const signInButton = await page.waitForSelector('button[type="submit"]', { timeout: 5000 })
        if (!signInButton) {
          // Try to find button with sign in text
          const buttons = await page.$$('button')
          let foundButton = null
          for (const btn of buttons) {
            const text = await page.evaluate(el => el.innerText || el.textContent, btn)
            if (text && (text.toLowerCase().includes('sign in') || text.toLowerCase().includes('login'))) {
              foundButton = btn
              break
            }
          }
          if (!foundButton) {
            throw new Error('Could not find sign in button')
          }
          await foundButton.click()
        } else {
          await signInButton.click()
        }
      } else {
        throw new Error('Could not find email input field')
      }
    } catch (e) {
      // Fallback: try to find email button first
      console.log('Fallback: looking for email button...')
      try {
        await page.waitForSelector('button', { timeout: 15000 })
        const buttons = await page.$$('button')
        let emailBtn = null
        
        // Look for email button with various text patterns
        for (const btn of buttons) {
          const text = await page.evaluate(el => el.innerText || el.textContent, btn)
          if (text && (
            text.trim().toLowerCase().includes('email') || 
            text.trim().toLowerCase().includes('sign in with email') ||
            text.trim().toLowerCase().includes('continue with email')
          )) {
            emailBtn = btn
            break
          }
        }
        
        if (emailBtn) {
          console.log('Found email button, clicking...')
          await emailBtn.click()
          await new Promise(res => setTimeout(res, 1000))
          
          // Now fill in the form
          const emailInput = await page.waitForSelector('input[name="username"], input[name="email"], input[type="email"], input[placeholder*="email" i]', { timeout: 10000 })
          if (!emailInput) {
            throw new Error('Could not find email input field after clicking email button')
          }
          await emailInput.click() // Click to focus
          await emailInput.type(TRADINGVIEW_EMAIL, { delay: 50 })
          
          const passwordInput = await page.waitForSelector('input[name="password"], input[type="password"], input[placeholder*="password" i]', { timeout: 5000 })
          if (!passwordInput) {
            throw new Error('Could not find password input field after clicking email button')
          }
          await passwordInput.click() // Click to focus
          await passwordInput.type(TRADINGVIEW_PASSWORD, { delay: 50 })
          
          const signInButton = await page.waitForSelector('button[type="submit"]', { timeout: 5000 })
          if (!signInButton) {
            // Try to find button with sign in text
            const buttons = await page.$$('button')
            let foundButton = null
            for (const btn of buttons) {
              const text = await page.evaluate(el => el.innerText || el.textContent, btn)
              if (text && (text.toLowerCase().includes('sign in') || text.toLowerCase().includes('login'))) {
                foundButton = btn
                break
              }
            }
            if (!foundButton) {
              throw new Error('Could not find sign in button after clicking email button')
            }
            await foundButton.click()
          } else {
            await signInButton.click()
          }
        } else {
          throw new Error('Could not find email button')
        }
      } catch (e2) {
        console.error('Could not find or click email button:', e2)
        const errorMessage = e2 instanceof Error ? e2.message : String(e2)
        throw new Error('Could not find or click email button on TradingView login page. ' + errorMessage)
      }
    }
    
    // Wait for navigation or dashboard (main page)
    try {
      console.log('Waiting for login to complete...')
      await page.waitForSelector('.tv-header__user-menu-button, .chart-container, [data-name="header-user-menu"]', { timeout: 30000 })
    } catch (e) {
      console.error('Login navigation did not complete.')
      throw new Error('Login navigation did not complete.')
    }
    
    console.log('TradingView login complete')
  }

  async capture(symbol: string, filename: string, layouts?: string[], timeframe?: string) {
    console.log('Working directory:', process.cwd())
    
    // Load settings and update if provided
    const settings = await settingsManager.loadSettings()
    if (symbol && symbol !== settings.symbol) {
      await settingsManager.setSymbol(symbol)
    }
    if (timeframe && timeframe !== settings.timeframe) {
      await settingsManager.setTimeframe(timeframe)
    }
    if (layouts && JSON.stringify(layouts) !== JSON.stringify(settings.layouts)) {
      await settingsManager.setLayouts(layouts)
    }
    
    // Use saved settings if not provided
    const finalSymbol = symbol || settings.symbol
    const finalTimeframe = timeframe || settings.timeframe
    const finalLayouts = layouts || settings.layouts
    
    console.log('Using settings:', { symbol: finalSymbol, timeframe: finalTimeframe, layouts: finalLayouts })
    
    const page = await this.init()
    
    // Capture screenshots for each layout
    const screenshots: string[] = []
    
    for (let i = 0; i < finalLayouts.length; i++) {
      const layout = finalLayouts[i]
      console.log(`Processing layout ${i + 1}/${finalLayouts.length}: ${layout}`)
      
      // Check if we have a direct URL for this layout
      const layoutUrlPath = LAYOUT_URLS[layout]
      if (layoutUrlPath) {
        // Use direct layout URL
        let url = `https://www.tradingview.com/chart/${layoutUrlPath}/?symbol=${finalSymbol}`
        if (finalTimeframe) {
          url += `&interval=${encodeURIComponent(finalTimeframe)}`
        }
        
        try {
          console.log('Navigating to layout URL:', url)
          await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 })
          console.log('Successfully navigated to layout:', layout)
        } catch (e: any) {
          console.error(`Failed to load layout "${layout}":`, e)
          throw new Error(`Failed to load layout "${layout}": ` + (e.message || e))
        }
      } else {
        // Fallback to loading layout via menu (for layouts without direct URLs)
        console.log(`No direct URL found for layout "${layout}", trying menu navigation...`)
        
        // Navigate to base chart URL first
        let url = `https://www.tradingview.com/chart/?symbol=${finalSymbol}`
        if (finalTimeframe) {
          url += `&interval=${encodeURIComponent(finalTimeframe)}`
        }
        
        try {
          console.log('Navigating to base chart URL:', url)
          await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 })
          console.log('Successfully navigated to base chart')
        } catch (e: any) {
          console.error('Failed to load TradingView chart page:', e)
          throw new Error('Failed to load TradingView chart page: ' + (e.message || e))
        }
        
        // Try to load the layout via menu
        await this.loadLayout(page, layout)
      }
      
      // Wait for layout to load
      await new Promise(res => setTimeout(res, 3000))
      
      // Generate filename for this layout
      const layoutFilename = filename.replace('.png', `_${layout}.png`)
      const screenshotsDir = path.join(process.cwd(), 'screenshots')
      await fs.mkdir(screenshotsDir, { recursive: true })
      const filePath = path.join(screenshotsDir, layoutFilename)
      
      try {
        await page.screenshot({ path: filePath as `${string}.png`, type: 'png' })
        console.log(`Screenshot saved for layout ${layout}:`, filePath)
        screenshots.push(filePath)
      } catch (e: any) {
        const debugScreenshotErrorPath = path.resolve(`debug_screenshot_error_${layout}.png`) as `${string}.png`
        await page.screenshot({ path: debugScreenshotErrorPath })
        console.error(`Failed to capture screenshot for layout ${layout}:`, e)
        console.error('Screenshot on screenshot error:', debugScreenshotErrorPath)
        throw new Error(`Failed to capture screenshot for layout ${layout}: ` + (e.message || e))
      }
    }
    
    return screenshots
  }

  private async loadLayout(page: Page, layout: string): Promise<void> {
    try {
      console.log('Loading layout using direct URL:', layout)
      
      // Check if we have a direct URL for this layout
      const layoutUrlPath = LAYOUT_URLS[layout]
      if (!layoutUrlPath) {
        console.log(`No direct URL found for layout "${layout}". Available layouts:`, Object.keys(LAYOUT_URLS))
        console.log('Skipping layout loading and continuing with default chart')
        return
      }
      
      // Construct the full URL for the layout
      const layoutUrl = `https://www.tradingview.com/chart/${layoutUrlPath}/`
      console.log('Navigating to layout URL:', layoutUrl)
      
      // Navigate directly to the layout URL
      await page.goto(layoutUrl, { waitUntil: 'networkidle2', timeout: 60000 })
      console.log('Successfully navigated to layout:', layout)
      
      // Wait for the layout to fully load
      await new Promise(res => setTimeout(res, 3000))
      
      // Take a screenshot after layout loads for debugging
      const debugAfterPath = path.resolve(`debug_after_layout_${layout.replace(/\s+/g, '_')}.png`) as `${string}.png`
      await page.screenshot({ path: debugAfterPath })
      console.log('After layout load screenshot saved:', debugAfterPath)
      
    } catch (e: any) {
      console.error(`Failed to load layout "${layout}":`, e)
      
      // Take debug screenshot on error
      const debugErrorPath = path.resolve(`debug_layout_error_${layout.replace(/\s+/g, '_')}.png`) as `${string}.png`
      await page.screenshot({ path: debugErrorPath })
      console.log('Layout error screenshot saved:', debugErrorPath)
      
      // Don't throw error, just continue with default chart
      console.log('Continuing with default chart layout...')
    }
  }
}

export const tradingViewCapture = new TradingViewCapture()
