/**
 * AutoLlama Auto-Setup System
 * 🦙 Automatic database initialization and first-run setup
 */

const chalk = require('chalk');
const ora = require('ora');
const fs = require('fs-extra');
const path = require('path');
const { DatabaseManager } = require('../database');
const { MigrationRunner } = require('../migrations/migration-runner');

class AutoSetup {
  constructor(config = {}) {
    this.config = {
      projectRoot: config.projectRoot || process.cwd(),
      skipPrompts: config.skipPrompts || false,
      verbose: config.verbose || false,
      ...config
    };
    
    this.setupState = {
      isFirstRun: false,
      needsMigration: false,
      needsConfiguration: false
    };
  }

  /**
   * Check if this is a first run and setup is needed
   */
  async checkFirstRun() {
    const indicators = {
      hasEnvFile: await fs.pathExists(path.join(this.config.projectRoot, '.env')),
      hasDatabase: await this.checkDatabaseExists(),
      hasData: await this.checkDataDirectory(),
      hasNodeModules: await fs.pathExists(path.join(this.config.projectRoot, 'node_modules'))
    };
    
    this.setupState.isFirstRun = !indicators.hasEnvFile || !indicators.hasDatabase;
    this.setupState.needsMigration = indicators.hasDatabase && !(await this.checkMigrationsApplied());
    this.setupState.needsConfiguration = !indicators.hasEnvFile;
    
    if (this.config.verbose) {
      console.log(chalk.gray('🦙 Setup check:'));
      console.log(chalk.gray(`  • Environment: ${indicators.hasEnvFile ? '✅' : '❌'}`));
      console.log(chalk.gray(`  • Database:    ${indicators.hasDatabase ? '✅' : '❌'}`));
      console.log(chalk.gray(`  • Data dir:    ${indicators.hasData ? '✅' : '❌'}`));
      console.log(chalk.gray(`  • Dependencies: ${indicators.hasNodeModules ? '✅' : '❌'}`));
    }
    
    return this.setupState;
  }

  /**
   * Run automatic setup if needed
   */
  async runAutoSetup() {
    const state = await this.checkFirstRun();
    
    if (!state.isFirstRun && !state.needsMigration) {
      if (this.config.verbose) {
        console.log(chalk.green('✅ AutoLlama is already configured'));
      }
      return { setup: false, reason: 'already_configured' };
    }
    
    console.log(chalk.cyan.bold('\n🦙 AutoLlama First-Run Setup'));
    
    if (state.isFirstRun) {
      console.log(chalk.yellow('Looks like this is your first time running AutoLlama!'));
      console.log(chalk.gray('Let me get everything set up for you...\n'));
    }
    
    try {
      // 1. Setup directories
      await this.setupDirectories();
      
      // 2. Generate configuration if needed
      if (state.needsConfiguration) {
        await this.generateConfiguration();
      }
      
      // 3. Initialize database
      await this.initializeDatabase();
      
      // 4. Run migrations
      if (state.needsMigration || state.isFirstRun) {
        await this.runMigrations();
      }
      
      // 5. Seed sample data if requested
      await this.seedSampleData();
      
      // 6. Finalize setup
      await this.finalizeSetup();
      
      console.log(chalk.green.bold('\n🎉 AutoLlama setup complete!'));
      return { setup: true, reason: 'first_run_completed' };
      
    } catch (error) {
      console.error(chalk.red.bold('\n❌ Auto-setup failed:'), error.message);
      throw error;
    }
  }

  async setupDirectories() {
    const spinner = ora('Creating directories...').start();
    
    const directories = [
      'data',
      'uploads', 
      'logs',
      'temp',
      'backups',
      'data/qdrant'
    ];
    
    for (const dir of directories) {
      await fs.ensureDir(path.join(this.config.projectRoot, dir));
    }
    
    spinner.succeed('Directories created');
  }

  async generateConfiguration() {
    const spinner = ora('Generating configuration...').start();
    
    const deploymentMode = process.env.DEPLOYMENT_MODE || 'local';
    
    const envContent = `# AutoLlama Configuration
# Generated by auto-setup on ${new Date().toISOString()}

# Deployment Configuration
DEPLOYMENT_MODE=${deploymentMode}

# AI Provider
OPENAI_API_KEY=your_openai_api_key_here
AI_PROVIDER=openai

# Database Configuration
${deploymentMode === 'local' ? 
`DATABASE_TYPE=sqlite
DATABASE_PATH=./data/autollama.db` :
`DATABASE_URL=postgresql://autollama:autollama@localhost:5432/autollama`}

# Vector Database
QDRANT_URL=http://localhost:6333

# Processing Configuration
ENABLE_CONTEXTUAL_EMBEDDINGS=true
CONTEXT_GENERATION_BATCH_SIZE=5

# Development Settings
NODE_ENV=development
LOG_LEVEL=info
DEBUG=false

# UI Configuration
LLAMA_PERSONALITY=friendly

# Server Configuration
PORT=3001
FRONTEND_PORT=8080
`;
    
    await fs.writeFile(path.join(this.config.projectRoot, '.env'), envContent);
    
    // Create .env.example for reference
    await fs.writeFile(
      path.join(this.config.projectRoot, '.env.example'),
      envContent.replace(/your_\w+_api_key_here/g, 'your_api_key_here')
    );
    
    spinner.succeed('Configuration generated');
  }

  async initializeDatabase() {
    const spinner = ora('Initializing database...').start();
    
    try {
      // Load environment
      require('dotenv').config({ path: path.join(this.config.projectRoot, '.env') });
      
      const dbConfig = this.getDatabaseConfig();
      const db = new DatabaseManager(dbConfig);
      
      await db.connect();
      
      // Test database connection
      await db.healthCheck();
      
      await db.disconnect();
      
      spinner.succeed(`Database initialized (${dbConfig.type})`);
      
    } catch (error) {
      spinner.fail('Database initialization failed');
      
      if (error.message.includes('ENOENT') && process.env.DATABASE_TYPE === 'sqlite') {
        // SQLite file doesn't exist yet - this is normal
        spinner.succeed('SQLite database will be created during migration');
      } else {
        throw error;
      }
    }
  }

  async runMigrations() {
    const spinner = ora('Running database migrations...').start();
    
    try {
      const migrationConfig = {
        databaseType: process.env.DATABASE_TYPE || 'sqlite',
        migrationsPath: path.join(this.config.projectRoot, 'migrations'),
        projectRoot: this.config.projectRoot
      };
      
      const runner = new MigrationRunner(migrationConfig);
      await runner.initialize();
      
      const result = await runner.runMigrations();
      
      if (result.executed > 0) {
        spinner.succeed(`Applied ${result.executed} migrations`);
      } else {
        spinner.succeed('Database is up to date');
      }
      
      await runner.close();
      
    } catch (error) {
      spinner.fail('Migration failed');
      throw error;
    }
  }

  async seedSampleData() {
    // Check if user wants sample data
    const configPath = path.join(this.config.projectRoot, 'autollama.config.js');
    let wantsSampleData = true;
    
    if (await fs.pathExists(configPath)) {
      try {
        const config = require(configPath);
        wantsSampleData = config.seedSampleData !== false;
      } catch {
        // Ignore config file errors
      }
    }
    
    if (!wantsSampleData) {
      return;
    }
    
    const spinner = ora('Adding sample documents...').start();
    
    try {
      const db = new DatabaseManager(this.getDatabaseConfig());
      await db.connect();
      
      // Sample documents
      const sampleDocs = [
        {
          url: 'sample://getting-started',
          title: 'Getting Started with AutoLlama',
          summary: 'Learn the basics of using your new RAG framework',
          chunk_text: 'Welcome to AutoLlama! This intelligent document processing system helps you build context-aware applications. Start by uploading documents, then ask questions to see the magic happen.',
          chunk_id: 'sample-getting-started-1',
          chunk_index: 0,
          content_type: 'documentation',
          processing_status: 'completed',
          record_type: 'chunk',
          main_topics: db.config.type === 'sqlite' ? 
            JSON.stringify(['welcome', 'tutorial', 'basics']) :
            ['welcome', 'tutorial', 'basics']
        },
        {
          url: 'sample://features',
          title: 'AutoLlama Features Overview',
          summary: 'Comprehensive guide to AutoLlama capabilities',
          chunk_text: 'AutoLlama provides contextual embeddings for better accuracy, intelligent document chunking, real-time processing, and seamless integration with popular tools. The framework supports multiple deployment modes from local development to enterprise production.',
          chunk_id: 'sample-features-1',
          chunk_index: 0,
          content_type: 'documentation',
          processing_status: 'completed',
          record_type: 'chunk',
          main_topics: db.config.type === 'sqlite' ? 
            JSON.stringify(['features', 'capabilities', 'integration']) :
            ['features', 'capabilities', 'integration']
        }
      ];
      
      for (const doc of sampleDocs) {
        await db.insert('processed_content', doc);
      }
      
      await db.disconnect();
      
      spinner.succeed(`Added ${sampleDocs.length} sample documents`);
      
    } catch (error) {
      spinner.warn('Sample data seeding skipped');
      // Don't fail setup if seeding fails
    }
  }

  async finalizeSetup() {
    const spinner = ora('Finalizing setup...').start();
    
    // Create .autollama file to mark setup as complete
    const setupInfo = {
      version: '3.0.0',
      setupDate: new Date().toISOString(),
      deploymentMode: process.env.DEPLOYMENT_MODE || 'local',
      databaseType: process.env.DATABASE_TYPE || 'sqlite'
    };
    
    await fs.writeJson(
      path.join(this.config.projectRoot, '.autollama'),
      setupInfo,
      { spaces: 2 }
    );
    
    spinner.succeed('Setup finalized');
  }

  // Utility methods
  async checkDatabaseExists() {
    const databaseType = process.env.DATABASE_TYPE || 'sqlite';
    
    if (databaseType === 'sqlite') {
      const dbPath = process.env.DATABASE_PATH || './data/autollama.db';
      return fs.pathExists(path.resolve(this.config.projectRoot, dbPath));
    } else {
      // For PostgreSQL, try to connect
      try {
        const { Pool } = require('pg');
        const pool = new Pool({ connectionString: process.env.DATABASE_URL });
        await pool.query('SELECT 1');
        await pool.end();
        return true;
      } catch {
        return false;
      }
    }
  }

  async checkDataDirectory() {
    const dataPath = path.join(this.config.projectRoot, 'data');
    return fs.pathExists(dataPath);
  }

  async checkMigrationsApplied() {
    try {
      const db = new DatabaseManager(this.getDatabaseConfig());
      await db.connect();
      
      const hasTable = await db.tableExists('migration_history');
      await db.disconnect();
      
      return hasTable;
    } catch {
      return false;
    }
  }

  getDatabaseConfig() {
    const databaseType = process.env.DATABASE_TYPE || 'sqlite';
    
    if (databaseType === 'sqlite') {
      return {
        type: 'sqlite',
        path: process.env.DATABASE_PATH || './data/autollama.db'
      };
    } else {
      return {
        type: 'postgresql',
        connectionString: process.env.DATABASE_URL
      };
    }
  }
}

/**
 * Middleware function to run auto-setup before server starts
 */
async function autoSetupMiddleware(req, res, next) {
  // Check if setup is needed (only on first request)
  if (!global.AUTOLLAMA_SETUP_CHECKED) {
    global.AUTOLLAMA_SETUP_CHECKED = true;
    
    try {
      const autoSetup = new AutoSetup({ skipPrompts: true });
      const result = await autoSetup.runAutoSetup();
      
      if (result.setup) {
        console.log(chalk.green('🦙 Auto-setup completed successfully'));
      }
    } catch (error) {
      console.warn(chalk.yellow('⚠️  Auto-setup failed, continuing anyway...'));
      console.warn(chalk.gray(error.message));
    }
  }
  
  next();
}

/**
 * CLI function to run setup manually
 */
async function runSetup(options = {}) {
  const autoSetup = new AutoSetup(options);
  return autoSetup.runAutoSetup();
}

module.exports = {
  AutoSetup,
  autoSetupMiddleware,
  runSetup
};