const fs = require('fs')
const path = require('path')
const inquirer = require('inquirer')
const chalk = require('chalk')
const ora = require('ora')
const { getConfig } = require('../lib/config')
const { createCodeLibrary, updateCodeLibrary, listCodeLibraries } = require('../lib/api')
const webTranspile = require('../lib/transpile')
const resolveWebCodeType = webTranspile.resolveWebCodeType
const { lint } = require('../lib/lint')
const {
  preprocessBilditTemplate,
  canonicalizeDoubleParenAsCastTemplates,
} = require('../lib/preprocessBilditTemplate')
const { captureScreenshotFromCode, screenshotToDataUrl } = require('../lib/screenshot')
const { createVersion } = require('../lib/version')

function extractSnippetId(filename) {
  // Extract snippet ID from filename (e.g., hero.jsx -> hero)
  const basename = path.basename(filename, path.extname(filename))
  // Remove .template suffix if present
  return basename.replace(/\.template$/, '')
}

function detectCodeType(filePath) {
  const ext = path.extname(filePath).toLowerCase()
  const extMap = {
    '.js': 'js',
    '.jsx': 'jsx',
    '.ts': 'ts',
    '.tsx': 'tsx',
    '.html': 'html',
  }
  return extMap[ext] || 'jsx'
}

async function findExistingCodeLibrary(appId, snippetId) {
  try {
    const templateLibs = await listCodeLibraries(appId)
    return templateLibs.find((lib) => lib.snippetId === snippetId)
  } catch (error) {
    return null
  }
}

async function uploadFile(filePath, options) {
  const spinner = ora(`Processing ${path.basename(filePath)}`).start()

  try {
    // Read file
    let code = fs.readFileSync(filePath, 'utf8')
    let codeType = resolveWebCodeType(code, detectCodeType(filePath))
    code = canonicalizeDoubleParenAsCastTemplates(code, codeType)
    const snippetId = options.snippetId || extractSnippetId(filePath)
    const appId = options.appId || getConfig('defaultAppId')

    if (!appId) {
      spinner.fail('App ID is required')
      throw new Error('App ID is required. Use --app-id or set default in config.')
    }

    // Preprocess BILDIT template vars ($(varName:Type="default")) so code can be linted and transpiled
    const codeForValidation = preprocessBilditTemplate(code, codeType)

    // Lint code
    spinner.text = 'Linting code...'
    const lintResult = await lint(codeForValidation, filePath)
    if (lintResult.errorCount > 0) {
      spinner.warn(`Found ${lintResult.errorCount} linting errors`)
      lintResult.issues
        .filter((i) => i.severity === 'error')
        .forEach((issue) => {
          console.log(chalk.red(`  Line ${issue.line}: ${issue.message}`))
        })
    }

    // Transpile code
    spinner.text = 'Transpiling code...'
    const transpiledCode = webTranspile(codeForValidation, codeType, snippetId)

    // Capture screenshot
    let imageUrl = options.image
    if (!imageUrl) {
      spinner.text = 'Capturing screenshot...'
      try {
        // Try to render the code as HTML for screenshot
        // For React components, we'd need to render them, but for now we'll use a placeholder
        const screenshot = await captureScreenshotFromCode(
          `<div style="padding: 20px; background: white;">${code.substring(0, 500)}</div>`,
          { maxWidth: 500 }
        )
        imageUrl = screenshotToDataUrl(screenshot)
      } catch (error) {
        spinner.warn(`Screenshot capture failed: ${error.message}`)
      }
    }

    // Find or create template
    spinner.text = 'Finding or creating template...'
    const existing = await findExistingCodeLibrary(appId, snippetId)

    const codeLibraryData = {
      name: options.name || snippetId,
      description: options.description || '',
      snippetId,
      type: options.type || 'component',
      codeType,
      code,
      appType: 'web', // Default to web for React/Next.js
      image: imageUrl,
      isCustom: true,
    }

    let cid
    if (existing) {
      spinner.text = 'Updating existing template...'
      await updateCodeLibrary(appId, existing.id, codeLibraryData)
      cid = existing.id
    } else {
      spinner.text = 'Creating new template...'
      const result = await createCodeLibrary(appId, codeLibraryData)
      cid = result.id || result
    }

    // Create version
    spinner.text = 'Creating version...'
    await createVersion(appId, cid, {
      code: {
        raw: code,
        compiled: transpiledCode,
      },
      codeType,
      image: imageUrl,
    })

    spinner.succeed(`Successfully uploaded ${path.basename(filePath)}`)
    return { cid, snippetId }
  } catch (error) {
    spinner.fail(`Failed to upload ${path.basename(filePath)}: ${error.message}`)
    throw error
  }
}

async function uploadCommand(files, options) {
  try {
    const filePaths = []
    
    // Expand folders to files
    for (const file of files) {
      const resolvedPath = path.resolve(file)
      const stat = fs.statSync(resolvedPath)
      
      if (stat.isDirectory()) {
        const dirFiles = fs.readdirSync(resolvedPath)
        dirFiles.forEach((f) => {
          const fullPath = path.join(resolvedPath, f)
          if (fs.statSync(fullPath).isFile() && /\.(js|jsx|ts|tsx|html)$/.test(f)) {
            filePaths.push(fullPath)
          }
        })
      } else {
        filePaths.push(resolvedPath)
      }
    }

    if (filePaths.length === 0) {
      console.error(chalk.red('No valid files found'))
      process.exit(1)
    }

    console.log(chalk.blue(`Found ${filePaths.length} file(s) to upload\n`))

    // Prompt for missing required options
    const config = getConfig()
    const prompt = inquirer.createPromptModule()
    const answers = await prompt([
      {
        type: 'input',
        name: 'appId',
        message: 'App ID:',
        default: options.appId || config.defaultAppId,
        when: !options.appId && !config.defaultAppId,
        validate: (input) => !!input || 'App ID is required',
      },
      {
        type: 'input',
        name: 'type',
        message: 'Template type:',
        default: options.type || 'component',
        when: !options.type,
      },
    ])

    const finalOptions = {
      ...options,
      ...answers,
    }

    // Upload each file
    for (const filePath of filePaths) {
      await uploadFile(filePath, finalOptions)
    }

    console.log(chalk.green('\n✓ All files uploaded successfully!'))
  } catch (error) {
    console.error(chalk.red(`\n✗ Upload failed: ${error.message}`))
    process.exit(1)
  }
}

module.exports = uploadCommand

