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[]
  sessionId?: string
  analyze?: boolean
}

// 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
  
  // Track active sessions for guaranteed cleanup
  private activeSessions: Set<TradingViewAutomation> = new Set()

  async captureWithLogin(config: ScreenshotConfig): Promise<string[]> {
    console.log('🚀 Enhanced Screenshot Service - Docker Environment (Dual Session with Robust Cleanup)')
    console.log('📋 Config:', config)

    const screenshotFiles: string[] = []
    const { sessionId } = config
    console.log('🔍 Enhanced Screenshot Service received sessionId:', sessionId)
    
    // Cleanup tracker for all sessions created in this operation
    const sessionCleanupTasks: Array<() => Promise<void>> = []
    
    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 with proper cleanup tracking
      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()
          
          // CRITICAL: Add to active sessions for guaranteed cleanup
          this.activeSessions.add(layoutSession)
          
          // Add cleanup task for this session
          sessionCleanupTasks.push(async () => {
            if (layoutSession) {
              console.log(`🧹 Cleaning up ${layout} session...`)
              try {
                await layoutSession.forceCleanup()
                this.activeSessions.delete(layoutSession)
                console.log(`✅ ${layout} session cleaned up`)
              } catch (cleanupError) {
                console.error(`❌ Error cleaning up ${layout} session:`, cleanupError)
              }
            }
          })
          
          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 credentials: TradingViewCredentials = {
              email: process.env.TRADINGVIEW_EMAIL!,
              password: process.env.TRADINGVIEW_PASSWORD!
            }
            
            const loginSuccess = await layoutSession.login(credentials)
            if (!loginSuccess) {
              throw new Error(`Failed to login to ${layout} session`)
            }
          } else {
            console.log(`✅ ${layout.toUpperCase()}: Already logged in`)
          }
          
          // 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)
              
              const directUrl = `https://www.tradingview.com/chart/?symbol=${config.symbol}&interval=${config.timeframe}&layout=${layoutUrl}`
              console.log(`🔗 ${layout.toUpperCase()}: Direct navigation to: ${directUrl}`)
              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(`Navigation to ${layout} layout failed after all attempts`)
          }
          
          // Wait for chart to load
          console.log(`⏳ ${layout.toUpperCase()}: Waiting for chart to load...`)
          
          if (sessionId && index === 0) {
            progressTracker.updateStep(sessionId, 'auth', 'completed', 'Authentication successful')
            progressTracker.updateStep(sessionId, 'loading', 'active', 'Loading chart data...')
          }
          
          try {
            // Wait for canvas elements (charts)
            await page.waitForSelector('canvas', { timeout: 30000 })
            console.log(`✅ ${layout.toUpperCase()}: Chart canvas found`)
          } catch (canvasError) {
            console.warn(`⚠️ ${layout.toUpperCase()}: Chart canvas not found, continuing anyway...`)
          }
          
          // Check if it's the primary session for loading progress updates
          if (sessionId && index === 0) {
            // Wait for chart data to fully load
            console.log(`⏳ ${layout.toUpperCase()}: Ensuring chart data is loaded...`)
            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.toUpperCase()}: Screenshot saved: ${screenshotFile}`)
              return screenshotFile
            } else {
              console.error(`❌ ${layout.toUpperCase()}: Screenshot failed - no file returned`)
              return null
            }
          } catch (screenshotError: any) {
            console.error(`❌ ${layout.toUpperCase()}: Screenshot capture failed:`, screenshotError?.message || screenshotError)
            return null
          }
          
        } 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)
      
      // 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
    } finally {
      // CRITICAL: Guaranteed cleanup of all sessions created in this operation
      console.log(`🧹 FINALLY BLOCK: Cleaning up ${sessionCleanupTasks.length} sessions...`)
      
      try {
        // Execute all cleanup tasks in parallel with timeout
        const cleanupPromises = sessionCleanupTasks.map(task => 
          Promise.race([
            task(),
            new Promise((_, reject) => 
              setTimeout(() => reject(new Error('Cleanup timeout')), 10000)
            )
          ]).catch(error => {
            console.error('Session cleanup error:', error)
          })
        )
        
        await Promise.allSettled(cleanupPromises)
        console.log('✅ FINALLY BLOCK: All session cleanups completed')
        
        // Additional aggressive cleanup to ensure no processes remain
        await this.forceKillRemainingProcesses()
        
      } catch (cleanupError) {
        console.error('❌ FINALLY BLOCK: Error during session cleanup:', cleanupError)
      }
    }
  }

  // Enhanced cleanup with force process termination
  private async forceKillRemainingProcesses(): Promise<void> {
    try {
      const { exec } = require('child_process')
      const { promisify } = require('util')
      const execAsync = promisify(exec)
      
      console.log('🔧 Force killing any remaining browser processes...')
      
      // Multiple kill strategies for thorough cleanup
      const killCommands = [
        'pkill -f "chromium.*--remote-debugging-port" 2>/dev/null || true',
        'pkill -f "chromium.*--user-data-dir" 2>/dev/null || true',
        'pkill -f "/usr/lib/chromium/chromium" 2>/dev/null || true',
        'pkill -f "chrome.*--remote-debugging-port" 2>/dev/null || true',
        // Clean up any zombie processes
        'pkill -9 -f "chromium.*defunct" 2>/dev/null || true'
      ]
      
      for (const command of killCommands) {
        try {
          await execAsync(command)
        } catch (killError) {
          // Ignore errors from kill commands as processes might not exist
        }
      }
      
      console.log('✅ Force process cleanup completed')
    } catch (error) {
      console.error('Error in force process cleanup:', error)
    }
  }

  async cleanup(): Promise<void> {
    console.log('🧹 Cleaning up parallel browser sessions...')
    
    const cleanupPromises = []
    
    // Cleanup all active sessions tracked in this instance
    for (const session of this.activeSessions) {
      cleanupPromises.push(
        session.forceCleanup().catch((err: any) => 
          console.error('Active session cleanup error:', err)
        )
      )
    }
    this.activeSessions.clear()
    
    // 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
    await this.forceKillRemainingProcesses()
  }

  // Keep existing methods for compatibility
  async captureQuick(symbol: string, timeframe: string, credentials?: TradingViewCredentials): Promise<string | null> {
    const automation = tradingViewAutomation
    
    try {
      await automation.init()
      
      if (credentials) {
        const loginSuccess = await automation.login(credentials)
        if (!loginSuccess) {
          throw new Error('Failed to login to TradingView')
        }
      }
      
      // Navigate to symbol and timeframe
      await automation.navigateToSymbol(symbol, timeframe)
      
      const filename = `${symbol}_${timeframe}_${Date.now()}.png`
      return await automation.takeScreenshot({ filename })
      
    } catch (error) {
      console.error('Quick capture failed:', error)
      throw error
    } finally {
      // Cleanup after quick capture
      try {
        await automation.forceCleanup()
      } catch (cleanupError) {
        console.error('Error in quick capture cleanup:', cleanupError)
      }
    }
  }

  async capture(symbol: string, filename: string): Promise<string[]> {
    let browser: Browser | null = null
    
    try {
      console.log(`Starting enhanced screenshot capture for ${symbol}...`);
      
      // Launch browser
      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
      });

      console.log(`Screenshot saved to: ${screenshotPath}`);
      return [screenshotPath];
      
    } catch (error) {
      console.error('Error capturing screenshot:', error);
      throw error;
    } finally {
      // CRITICAL: Always cleanup browser in finally block
      if (browser) {
        try {
          await browser.close();
          console.log('✅ Browser closed in finally block');
        } catch (cleanupError) {
          console.error('Error closing browser in finally block:', cleanupError);
        }
      }
    }
  }

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

export const enhancedScreenshotService = new EnhancedScreenshotService()
