import { tradingViewAutomation, TradingViewAutomation, TradingViewCredentials, NavigationOptions } from './tradingview-automation'
import fs from 'fs/promises'
import path from 'path'
import puppeteer from 'puppeteer'
import { Browser, Page } from 'puppeteer'
import { progressTracker, ProgressStep } from './progress-tracker'

export interface ScreenshotConfig {
  symbol: string
  timeframe: string
  layouts?: string[] // Multiple chart layouts if needed
  credentials?: TradingViewCredentials // Optional if using .env
  sessionId?: string // For progress tracking
}

// Layout URL mappings for direct navigation
const LAYOUT_URLS = {
  'ai': 'Z1TzpUrf',
  'diy': 'vWVvjLhP',
  'Diy module': 'vWVvjLhP' // Alternative mapping for 'Diy module'
}

export class EnhancedScreenshotService {
  private static readonly OPERATION_TIMEOUT = 120000 // 2 minutes timeout for Docker
  private static aiSession: TradingViewAutomation | null = null
  private static diySession: TradingViewAutomation | null = null

  async captureWithLogin(config: ScreenshotConfig): Promise<string[]> {
    console.log('🚀 Enhanced Screenshot Service - Docker Environment (Dual Session)')
    console.log('📋 Config:', config)
    
    const screenshotFiles: string[] = []
    const { sessionId } = config
    console.log('🔍 Enhanced Screenshot Service received sessionId:', sessionId)
    
    // Progress tracking (session already created in API)
    if (sessionId) {
      progressTracker.updateStep(sessionId, 'init', 'active', 'Starting browser sessions...')
    }
    
    try {
      // Ensure screenshots directory exists
      const screenshotsDir = path.join(process.cwd(), 'screenshots')
      await fs.mkdir(screenshotsDir, { recursive: true })

      const timestamp = Date.now()
      const layoutsToCapture = config.layouts || ['ai', 'diy']
      
      console.log(`\n🔄 Starting parallel capture of ${layoutsToCapture.length} layouts...`)
      
      if (sessionId) {
        progressTracker.updateStep(sessionId, 'init', 'completed', `Started ${layoutsToCapture.length} browser sessions`)
        progressTracker.updateStep(sessionId, 'auth', 'active', 'Authenticating with TradingView...')
      }
      
      // Create parallel session promises for true dual-session approach
      const activeSessions: TradingViewAutomation[] = []
      const sessionPromises = layoutsToCapture.map(async (layout, index) => {
        const layoutKey = layout.toLowerCase()
        let layoutSession: TradingViewAutomation | null = null
        
        try {
          console.log(`\n🔧 Initializing ${layout.toUpperCase()} session (parallel)...`)
          
          // Get layout URL with better error handling
          let layoutUrl = LAYOUT_URLS[layoutKey as keyof typeof LAYOUT_URLS]
          
          // Try alternative key for 'Diy module'
          if (!layoutUrl && layout === 'Diy module') {
            layoutUrl = LAYOUT_URLS['diy']
          }
          
          if (!layoutUrl) {
            throw new Error(`No URL mapping found for layout: ${layout} (tried keys: ${layoutKey}, diy)`)
          }
          
          console.log(`🗺️ ${layout.toUpperCase()}: Using layout URL ${layoutUrl}`)
          
          // Create a dedicated automation instance for this layout
          layoutSession = new TradingViewAutomation()
          activeSessions.push(layoutSession) // Track for cleanup
          
          console.log(`🐳 Starting ${layout} browser session...`)
          await layoutSession.init()
          
          // Check login status and login if needed
          const isLoggedIn = await layoutSession.checkLoginStatus()
          if (!isLoggedIn) {
            console.log(`🔐 Logging in to ${layout} session...`)
            if (sessionId && index === 0) {
              progressTracker.updateStep(sessionId, 'auth', 'active', `Logging into ${layout} session...`)
            }
            const loginSuccess = await layoutSession.login(config.credentials)
            if (!loginSuccess) {
              throw new Error(`Failed to login to ${layout} session`)
            }
          } else {
            console.log(`✅ ${layout} session already logged in`)
          }
          
          // Update auth progress when first session completes auth
          if (sessionId && index === 0) {
            progressTracker.updateStep(sessionId, 'auth', 'completed', 'TradingView authentication successful')
            progressTracker.updateStep(sessionId, 'navigation', 'active', `Navigating to ${config.symbol} chart...`)
          }
          
          // Navigate directly to the specific layout URL with symbol and timeframe
          const directUrl = `https://www.tradingview.com/chart/${layoutUrl}/?symbol=${config.symbol}&interval=${config.timeframe}`
          console.log(`🌐 ${layout.toUpperCase()}: Navigating directly to ${directUrl}`)
          
          // Get page from the session
          const page = (layoutSession as any).page
          if (!page) {
            throw new Error(`Failed to get page for ${layout} session`)
          }
          
          // Navigate directly to the layout URL with retries and progressive timeout strategy
          let navigationSuccess = false
          for (let attempt = 1; attempt <= 3; attempt++) {
            try {
              console.log(`🔄 ${layout.toUpperCase()}: Navigation attempt ${attempt}/3`)
              
              // Progressive waiting strategy: first try domcontentloaded, then networkidle if that fails
              const waitUntilStrategy = attempt === 1 ? 'domcontentloaded' : 'networkidle0'
              const timeoutDuration = attempt === 1 ? 30000 : (60000 + (attempt - 1) * 30000)
              
              console.log(`📋 ${layout.toUpperCase()}: Using waitUntil: ${waitUntilStrategy}, timeout: ${timeoutDuration}ms`)
              
              await page.goto(directUrl, { 
                waitUntil: waitUntilStrategy,
                timeout: timeoutDuration 
              })
              
              // If we used domcontentloaded, wait a bit more for dynamic content
              if (waitUntilStrategy === 'domcontentloaded') {
                console.log(`⏳ ${layout.toUpperCase()}: Waiting additional 5s for dynamic content...`)
                await new Promise(resolve => setTimeout(resolve, 5000))
              }
              
              navigationSuccess = true
              break
            } catch (navError: any) {
              console.warn(`⚠️ ${layout.toUpperCase()}: Navigation attempt ${attempt} failed:`, navError?.message || navError)
              if (attempt === 3) {
                throw new Error(`Failed to navigate to ${layout} layout after 3 attempts: ${navError?.message || navError}`)
              }
              // Progressive backoff
              const waitTime = 2000 * attempt
              console.log(`⏳ ${layout.toUpperCase()}: Waiting ${waitTime}ms before retry...`)
              await new Promise(resolve => setTimeout(resolve, waitTime))
            }
          }
          
          if (!navigationSuccess) {
            throw new Error(`Failed to navigate to ${layout} layout`)
          }
          
          console.log(`✅ ${layout.toUpperCase()}: Successfully navigated to layout`)
          
          // Update navigation progress when first session completes navigation
          if (sessionId && index === 0) {
            progressTracker.updateStep(sessionId, 'navigation', 'completed', 'Chart navigation successful')
            progressTracker.updateStep(sessionId, 'loading', 'active', 'Loading chart data and indicators...')
          }
          
          // Progressive loading strategy: shorter initial wait, then chart-specific wait
          console.log(`⏳ ${layout.toUpperCase()}: Initial page stabilization (2s)...`)
          await new Promise(resolve => setTimeout(resolve, 2000))
          
          // Wait for chart to load with multiple strategies
          console.log(`⏳ ${layout.toUpperCase()}: Waiting for chart to load...`)
          let chartLoadSuccess = false
          
          try {
            // Strategy 1: Wait for chart to load with timeout
            await Promise.race([
              new Promise(resolve => setTimeout(resolve, 10000)), // Wait 10 seconds for chart
              new Promise((_, reject) => setTimeout(() => reject(new Error('Chart data timeout')), 30000))
            ])
            console.log(`✅ ${layout.toUpperCase()}: Chart loaded successfully`)
            chartLoadSuccess = true
          } catch (chartError: any) {
            console.warn(`⚠️ ${layout.toUpperCase()}: Chart data wait failed:`, chartError?.message || chartError)
            
            // Strategy 2: Look for chart elements manually
            try {
              console.log(`🔍 ${layout.toUpperCase()}: Checking for chart elements manually...`)
              await page.waitForSelector('.layout__area--center', { timeout: 15000 })
              console.log(`✅ ${layout.toUpperCase()}: Chart area found via selector`)
              chartLoadSuccess = true
            } catch (selectorError: any) {
              console.warn(`⚠️ ${layout.toUpperCase()}: Chart selector check failed:`, selectorError?.message || selectorError)
            }
          }
          
          if (!chartLoadSuccess) {
            console.warn(`⚠️ ${layout.toUpperCase()}: Chart loading uncertain, proceeding with fallback wait...`)
            await new Promise(resolve => setTimeout(resolve, 8000))
          } else {
            // Additional stabilization wait after chart loads
            console.log(`⏳ ${layout.toUpperCase()}: Chart stabilization (3s)...`)
            await new Promise(resolve => setTimeout(resolve, 3000))
          }
          
          // Update loading progress when first session completes loading
          if (sessionId && index === 0) {
            progressTracker.updateStep(sessionId, 'loading', 'completed', 'Chart data loaded successfully')
            progressTracker.updateStep(sessionId, 'capture', 'active', 'Capturing screenshots...')
          }
          
          // Take screenshot with better error handling
          const filename = `${config.symbol}_${config.timeframe}_${layout}_${timestamp}.png`
          console.log(`📸 Taking ${layout} screenshot: ${filename}`)
          
          let screenshotFile = null
          try {
            screenshotFile = await layoutSession.takeScreenshot({ filename })
            if (screenshotFile) {
              console.log(`✅ ${layout} screenshot captured: ${screenshotFile}`)
            } else {
              throw new Error(`Screenshot file was not created for ${layout}`)
            }
          } catch (screenshotError: any) {
            console.error(`❌ ${layout.toUpperCase()}: Screenshot failed:`, screenshotError?.message || screenshotError)
            throw new Error(`Failed to capture ${layout} screenshot: ${screenshotError?.message || screenshotError}`)
          }
          
          // Store session for potential reuse
          if (layout === 'ai' || layoutKey === 'ai') {
            EnhancedScreenshotService.aiSession = layoutSession
          } else if (layout === 'diy' || layoutKey === 'diy' || layout === 'Diy module') {
            EnhancedScreenshotService.diySession = layoutSession
          }
          
          return screenshotFile
          
        } catch (error: any) {
          console.error(`❌ Error capturing ${layout} layout:`, error?.message || error)
          console.error(`❌ Full ${layout} error details:`, error)
          console.error(`❌ ${layout} error stack:`, error?.stack)
          
          // Attempt to capture browser state for debugging
          try {
            const page = (layoutSession as any)?.page
            if (page) {
              const url = await page.url()
              const title = await page.title()
              console.error(`❌ ${layout} browser state - URL: ${url}, Title: ${title}`)
              
              // Try to get page content for debugging
              const bodyText = await page.evaluate(() => document.body.innerText.slice(0, 200))
              console.error(`❌ ${layout} page content preview:`, bodyText)
            }
          } catch (debugError: any) {
            console.error(`❌ Failed to capture ${layout} browser state:`, debugError?.message || debugError)
          }
          
          throw error // Re-throw to be caught by Promise.allSettled
        }
      })
      
      // Execute all sessions in parallel and wait for completion
      console.log(`\n⚡ Executing ${layoutsToCapture.length} sessions in parallel...`)
      const results = await Promise.allSettled(sessionPromises)
      
      // Cleanup all sessions after capture (success or failure)
      console.log('🧹 Cleaning up all browser sessions...')
      await Promise.allSettled(
        activeSessions.map(async (session, index) => {
          try {
            const layout = layoutsToCapture[index]
            console.log(`🧹 Cleaning up ${layout} session...`)
            await session.forceCleanup()
          } catch (cleanupError) {
            console.warn(`⚠️ Cleanup failed for session ${index}:`, cleanupError)
          }
        })
      )
      
      // Collect successful screenshots
      results.forEach((result, index) => {
        const layout = layoutsToCapture[index]
        if (result.status === 'fulfilled' && result.value) {
          screenshotFiles.push(result.value)
          console.log(`✅ ${layout} parallel session completed successfully`)
        } else {
          console.error(`❌ ${layout} parallel session failed:`, result.status === 'rejected' ? result.reason : 'Unknown error')
        }
      })
      
      if (sessionId) {
        progressTracker.updateStep(sessionId, 'capture', 'completed', `Captured ${screenshotFiles.length}/${layoutsToCapture.length} screenshots`)
      }
      
      console.log(`\n🎯 Parallel capture completed: ${screenshotFiles.length}/${layoutsToCapture.length} screenshots`)
      return screenshotFiles
      
    } catch (error) {
      console.error('Enhanced parallel screenshot capture failed:', error)
      
      if (sessionId) {
        // Mark the current active step as error
        const progress = progressTracker.getProgress(sessionId)
        if (progress) {
          const activeStep = progress.steps.find(step => step.status === 'active')
          if (activeStep) {
            progressTracker.updateStep(sessionId, activeStep.id, 'error', error instanceof Error ? error.message : 'Unknown error')
          }
        }
      }
      
      throw error
    }
  }

  async captureQuick(symbol: string, timeframe: string, credentials?: TradingViewCredentials): Promise<string | null> {
    try {
      console.log(`Starting quick screenshot capture for ${symbol} ${timeframe}...`);
      
      // Use the existing captureWithLogin method with a single default layout
      const config: ScreenshotConfig = {
        symbol,
        timeframe,
        layouts: ['ai'], // Default to AI layout for quick capture
        credentials
      };
      
      const screenshots = await this.captureWithLogin(config);
      
      // Return the first screenshot path or null if none captured
      return screenshots.length > 0 ? screenshots[0] : null;
      
    } catch (error) {
      console.error('Error in quick screenshot capture:', error);
      return null;
    }
  }

  async capture(symbol: string, filename: string): Promise<string[]> {
    try {
      console.log(`Starting enhanced screenshot capture for ${symbol}...`);
      
      // Launch browser
      const browser = await puppeteer.launch({
        headless: true,
        executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined,
        args: [
          '--no-sandbox',
          '--disable-setuid-sandbox',
          '--disable-dev-shm-usage',
          '--disable-accelerated-2d-canvas',
          '--no-first-run',
          '--no-zygote',
          '--disable-gpu'
        ]
      });

      const page = await browser.newPage();
      await page.setViewport({ width: 1920, height: 1080 });

      // Navigate to TradingView chart
      await page.goto('https://www.tradingview.com/chart/', { 
        waitUntil: 'networkidle0',
        timeout: 30000 
      });

      // Wait for chart to load
      await page.waitForSelector('canvas', { timeout: 30000 });
      await new Promise(resolve => setTimeout(resolve, 3000));

      // Ensure screenshots directory exists
      const screenshotsDir = path.join(process.cwd(), 'screenshots')
      await fs.mkdir(screenshotsDir, { recursive: true })

      // Take screenshot
      const screenshotPath = path.join(screenshotsDir, filename);
      await page.screenshot({
        path: screenshotPath as `${string}.png`,
        type: 'png',
        fullPage: false
      });

      await browser.close();

      console.log(`Screenshot saved to: ${screenshotPath}`);
      return [screenshotPath];
    } catch (error) {
      console.error('Error capturing screenshot:', error);
      throw error;
    }
  }

  async cleanup(): Promise<void> {
    console.log('🧹 Cleaning up parallel browser sessions...')
    
    const cleanupPromises = []
    
    // Cleanup dedicated AI session if exists
    if (EnhancedScreenshotService.aiSession) {
      console.log('🔧 Cleaning up AI session...')
      cleanupPromises.push(
        EnhancedScreenshotService.aiSession.forceCleanup().catch((err: any) => 
          console.error('AI session cleanup error:', err)
        )
      )
      EnhancedScreenshotService.aiSession = null
    }
    
    // Cleanup dedicated DIY session if exists
    if (EnhancedScreenshotService.diySession) {
      console.log('🔧 Cleaning up DIY session...')
      cleanupPromises.push(
        EnhancedScreenshotService.diySession.forceCleanup().catch((err: any) => 
          console.error('DIY session cleanup error:', err)
        )
      )
      EnhancedScreenshotService.diySession = null
    }
    
    // Also cleanup the main singleton session
    cleanupPromises.push(
      tradingViewAutomation.forceCleanup().catch((err: any) => 
        console.error('Main session cleanup error:', err)
      )
    )
    
    // Wait for all cleanup operations to complete
    await Promise.allSettled(cleanupPromises)
    
    // Give browsers time to fully close
    await new Promise(resolve => setTimeout(resolve, 3000))
    
    console.log('✅ All parallel browser sessions cleaned up')
    
    // Force kill any remaining browser processes
    try {
      const { exec } = require('child_process')
      const { promisify } = require('util')
      const execAsync = promisify(exec)
      
      console.log('🔧 Force killing any remaining browser processes...')
      await execAsync('pkill -f "chromium.*--remote-debugging-port" 2>/dev/null || true')
      await execAsync('pkill -f "chrome.*--remote-debugging-port" 2>/dev/null || true')
      console.log('✅ Remaining browser processes terminated')
    } catch (processKillError) {
      console.error('Error force killing browser processes:', processKillError)
    }
  }

  async healthCheck(): Promise<{ status: 'healthy' | 'error', message?: string }> {
    try {
      // Simple health check - try to launch a browser instance
      const browser = await puppeteer.launch({
        headless: true,
        executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || undefined,
        args: [
          '--no-sandbox',
          '--disable-setuid-sandbox',
          '--disable-dev-shm-usage',
        ]
      });
      
      await browser.close();
      
      return { status: 'healthy' };
    } catch (error) {
      return { 
        status: 'error', 
        message: error instanceof Error ? error.message : 'Unknown error'
      };
    }
  }
}

export const enhancedScreenshotService = new EnhancedScreenshotService()