#!/usr/bin/env node

import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
import { execSync } from 'child_process';
import mongoose from 'mongoose';
import dotenv from 'dotenv';
// Load environment variables
dotenv.config({ path: '.env.local' });

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.dirname(__dirname);
const funnelsDir = path.join(projectRoot, 'public', 'funnels');

// MongoDB connection URI
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/witlab-funnel';

// Mongoose schemas (same as in import script)
const FunnelDataSchema = new mongoose.Schema({
  meta: {
    id: { type: String, required: true },
    version: String,
    title: String,
    description: String,
    firstScreenId: String
  },
  defaultTexts: {
    nextButton: { type: String, default: 'Next' },
    continueButton: { type: String, default: 'Continue' }
  },
  screens: [mongoose.Schema.Types.Mixed]
}, { _id: false });

const FunnelSchema = new mongoose.Schema({
  funnelData: { 
    type: FunnelDataSchema, 
    required: true
  },
  name: { 
    type: String, 
    required: true,
    trim: true,
    maxlength: 200
  },
  description: {
    type: String,
    trim: true,
    maxlength: 1000
  },
  status: { 
    type: String, 
    enum: ['draft', 'published', 'archived'],
    default: 'draft',
    required: true
  },
  version: { 
    type: Number, 
    default: 1,
    min: 1
  },
  createdBy: { type: String, default: 'system' },
  lastModifiedBy: { type: String, default: 'system' },
  usage: {
    totalViews: { type: Number, default: 0, min: 0 },
    totalCompletions: { type: Number, default: 0, min: 0 },
    lastUsed: Date
  }
}, { 
  timestamps: true,
  collection: 'funnels'
});

const Funnel = mongoose.model('Funnel', FunnelSchema);

// Schema for images
const ImageSchema = new mongoose.Schema({
  filename: {
    type: String,
    required: true,
    unique: true,
    trim: true
  },
  originalName: {
    type: String,
    required: true,
    trim: true
  },
  mimetype: {
    type: String,
    required: true
  },
  size: {
    type: Number,
    required: true
  },
  data: {
    type: Buffer,
    required: true
  },
  uploadedAt: {
    type: Date,
    default: Date.now
  },
  uploadedBy: {
    type: String,
    default: 'admin'
  },
  funnelId: {
    type: String,
    index: { sparse: true }
  },
  description: {
    type: String,
    maxlength: 500
  }
}, {
  timestamps: true,
  collection: 'images'
});

const Image = mongoose.model('Image', ImageSchema);

async function downloadImagesFromDatabase(funnels) {
  const imagesDir = path.join(projectRoot, 'public', 'images');
  
  try {
    // Создаем папку для изображений
    await fs.mkdir(imagesDir, { recursive: true });
    console.log('📁 Created images directory');

    // Собираем все ссылки на изображения из воронок
    const imageUrls = new Set();
    
    for (const funnel of funnels) {
      for (const screen of funnel.funnelData.screens) {
        // Проверяем основной icon экрана (info экраны)
        if (screen.icon?.type === 'image' && screen.icon.value?.startsWith('/api/images/')) {
          imageUrls.add(screen.icon.value);
        }
        
        // Проверяем image экрана (email экраны)
        if (screen.image?.src?.startsWith('/api/images/')) {
          imageUrls.add(screen.image.src);
        }
        
        // Проверяем soulmatePortraitsDelivered (soulmate экраны)
        if (screen.soulmatePortraitsDelivered?.image?.startsWith('/api/images/')) {
          imageUrls.add(screen.soulmatePortraitsDelivered.image);
        }
        if (screen.soulmatePortraitsDelivered?.mediaUrl?.startsWith('/api/images/')) {
          imageUrls.add(screen.soulmatePortraitsDelivered.mediaUrl);
        }
        
        // Проверяем icon и image в вариантах экрана
        if (screen.variants && Array.isArray(screen.variants)) {
          for (const variant of screen.variants) {
            // icon в вариантах (info экраны)
            // В вариантах может не быть поля type, проверяем только value
            if (variant.overrides?.icon?.value?.startsWith('/api/images/')) {
              imageUrls.add(variant.overrides.icon.value);
            }
            // image в вариантах (email экраны)
            if (variant.overrides?.image?.src?.startsWith('/api/images/')) {
              imageUrls.add(variant.overrides.image.src);
            }
            // soulmatePortraitsDelivered в вариантах (soulmate экраны)
            if (variant.overrides?.soulmatePortraitsDelivered?.image?.startsWith('/api/images/')) {
              imageUrls.add(variant.overrides.soulmatePortraitsDelivered.image);
            }
            if (variant.overrides?.soulmatePortraitsDelivered?.mediaUrl?.startsWith('/api/images/')) {
              imageUrls.add(variant.overrides.soulmatePortraitsDelivered.mediaUrl);
            }
          }
        }
      }
    }

    if (imageUrls.size === 0) {
      console.log('ℹ️  No images to download');
      return {};
    }

    console.log(`🖼️  Found ${imageUrls.size} images to download`);

    // Скачиваем каждое изображение из БД
    const imageMapping = {};
    
    for (const imageUrl of imageUrls) {
      const filename = imageUrl.replace('/api/images/', '');
      
      try {
        const image = await Image.findOne({ filename }).lean();
        
        if (image) {
          const localPath = path.join(imagesDir, filename);
          
          // Преобразуем MongoDB Binary в Buffer
          let buffer;
          if (Buffer.isBuffer(image.data)) {
            buffer = image.data;
          } else if (image.data?.buffer) {
            // BSON Binary объект имеет свойство buffer
            buffer = Buffer.from(image.data.buffer);
          } else if (image.data instanceof Uint8Array) {
            buffer = Buffer.from(image.data);
          } else {
            // Fallback - пробуем напрямую преобразовать
            buffer = Buffer.from(image.data);
          }
          
          await fs.writeFile(localPath, buffer);
          
          // Создаем маппинг: старый URL → новый локальный путь
          imageMapping[imageUrl] = `/images/${filename}`;
          console.log(`💾 Downloaded ${filename} (${buffer.length} bytes)`);
        } else {
          console.warn(`⚠️  Image not found in database: ${filename}`);
        }
      } catch (error) {
        console.error(`❌ Error downloading ${filename}:`, error.message);
      }
    }

    return imageMapping;
  } catch (error) {
    console.error('❌ Error downloading images:', error.message);
    return {};
  }
}

function updateImageUrlsInFunnels(funnels, imageMapping) {
  for (const funnel of funnels) {
    for (const screen of funnel.funnelData.screens) {
      // Обновляем основной icon экрана (info экраны)
      if (screen.icon?.type === 'image' && screen.icon.value && imageMapping[screen.icon.value]) {
        const oldUrl = screen.icon.value;
        const newUrl = imageMapping[oldUrl];
        screen.icon.value = newUrl;
        console.log(`🔗 Updated image URL: ${oldUrl} → ${newUrl}`);
      }
      
      // Обновляем image экрана (email экраны)
      if (screen.image?.src && imageMapping[screen.image.src]) {
        const oldUrl = screen.image.src;
        const newUrl = imageMapping[oldUrl];
        screen.image.src = newUrl;
        console.log(`🔗 Updated image URL: ${oldUrl} → ${newUrl}`);
      }
      
      // Обновляем soulmatePortraitsDelivered (soulmate экраны)
      if (screen.soulmatePortraitsDelivered?.image && imageMapping[screen.soulmatePortraitsDelivered.image]) {
        const oldUrl = screen.soulmatePortraitsDelivered.image;
        const newUrl = imageMapping[oldUrl];
        screen.soulmatePortraitsDelivered.image = newUrl;
        console.log(`🔗 Updated soulmate image URL: ${oldUrl} → ${newUrl}`);
      }
      if (screen.soulmatePortraitsDelivered?.mediaUrl && imageMapping[screen.soulmatePortraitsDelivered.mediaUrl]) {
        const oldUrl = screen.soulmatePortraitsDelivered.mediaUrl;
        const newUrl = imageMapping[oldUrl];
        screen.soulmatePortraitsDelivered.mediaUrl = newUrl;
        console.log(`🔗 Updated soulmate mediaUrl: ${oldUrl} → ${newUrl}`);
      }
      
      // Обновляем icon и image в вариантах экрана
      if (screen.variants && Array.isArray(screen.variants)) {
        for (const variant of screen.variants) {
          // icon в вариантах (info экраны)
          // В вариантах может не быть поля type, проверяем только value
          if (variant.overrides?.icon?.value && imageMapping[variant.overrides.icon.value]) {
            const oldUrl = variant.overrides.icon.value;
            const newUrl = imageMapping[oldUrl];
            variant.overrides.icon.value = newUrl;
            console.log(`🔗 Updated variant image URL: ${oldUrl} → ${newUrl}`);
          }
          // image в вариантах (email экраны)
          if (variant.overrides?.image?.src && imageMapping[variant.overrides.image.src]) {
            const oldUrl = variant.overrides.image.src;
            const newUrl = imageMapping[oldUrl];
            variant.overrides.image.src = newUrl;
            console.log(`🔗 Updated variant image URL: ${oldUrl} → ${newUrl}`);
          }
          // soulmatePortraitsDelivered в вариантах (soulmate экраны)
          if (variant.overrides?.soulmatePortraitsDelivered?.image && imageMapping[variant.overrides.soulmatePortraitsDelivered.image]) {
            const oldUrl = variant.overrides.soulmatePortraitsDelivered.image;
            const newUrl = imageMapping[oldUrl];
            variant.overrides.soulmatePortraitsDelivered.image = newUrl;
            console.log(`🔗 Updated variant soulmate image URL: ${oldUrl} → ${newUrl}`);
          }
          if (variant.overrides?.soulmatePortraitsDelivered?.mediaUrl && imageMapping[variant.overrides.soulmatePortraitsDelivered.mediaUrl]) {
            const oldUrl = variant.overrides.soulmatePortraitsDelivered.mediaUrl;
            const newUrl = imageMapping[oldUrl];
            variant.overrides.soulmatePortraitsDelivered.mediaUrl = newUrl;
            console.log(`🔗 Updated variant soulmate mediaUrl: ${oldUrl} → ${newUrl}`);
          }
        }
      }
    }
  }
}

async function connectDB() {
  try {
    await mongoose.connect(MONGODB_URI);
    console.log('✅ Connected to MongoDB');
  } catch (error) {
    console.error('❌ MongoDB connection failed:', error.message);
    process.exit(1);
  }
}

async function ensureFunnelsDir() {
  try {
    await fs.access(funnelsDir);
  } catch {
    await fs.mkdir(funnelsDir, { recursive: true });
    console.log('📁 Created funnels directory');
  }
}

async function clearFunnelsDir() {
  try {
    const files = await fs.readdir(funnelsDir);
    for (const file of files) {
      if (file.endsWith('.json')) {
        await fs.unlink(path.join(funnelsDir, file));
      }
    }
    console.log('🧹 Cleared existing JSON files');
  } catch (error) {
    console.error('⚠️  Error clearing funnels directory:', error.message);
  }
}

async function getLatestPublishedFunnels() {
  try {
    // Группируем по funnelData.meta.id и берем последнюю версию каждой опубликованной воронки
    const latestFunnels = await Funnel.aggregate([
      // Фильтруем только опубликованные воронки
      { $match: { status: 'published' } },
      
      // Сортируем по версии в убывающем порядке
      { $sort: { 'funnelData.meta.id': 1, version: -1 } },
      
      // Группируем по ID воронки и берем первый документ (с наибольшей версией)
      {
        $group: {
          _id: '$funnelData.meta.id',
          latestFunnel: { $first: '$$ROOT' }
        }
      },
      
      // Заменяем корневой документ на latestFunnel
      { $replaceRoot: { newRoot: '$latestFunnel' } }
    ]);

    console.log(`📊 Found ${latestFunnels.length} latest published funnels`);
    return latestFunnels;
  } catch (error) {
    console.error('❌ Error fetching funnels:', error.message);
    throw error;
  }
}

/**
 * Нормализует данные воронки перед сохранением
 * Удаляет лишние поля которые не соответствуют типам TypeScript
 */
function normalizeFunnelData(funnelData) {
  return {
    ...funnelData,
    screens: funnelData.screens.map((screen) => {
      const normalizedScreen = { ...screen };
      
      // Удаляем поле 'show' из description (TypographyVariant не содержит его)
      // Поле 'show' есть только у TitleDefinition и SubtitleDefinition
      if (normalizedScreen.description && typeof normalizedScreen.description === 'object') {
        if ('show' in normalizedScreen.description) {
          delete normalizedScreen.description.show;
        }
      }
      
      // Удаляем специфичные для других шаблонов поля
      // Каждый шаблон должен содержать только свои поля
      switch (normalizedScreen.template) {
        case 'form':
          // fields нужно только для form экранов
          break;
        case 'email':
          // email имеет emailInput, а не fields
          if ('fields' in normalizedScreen) delete normalizedScreen.fields;
          if ('list' in normalizedScreen) delete normalizedScreen.list;
          break;
        case 'list':
          // list нужно только для list экранов
          if ('fields' in normalizedScreen) delete normalizedScreen.fields;
          break;
        case 'loaders':
          // progressbars нужно только для loaders
          if ('fields' in normalizedScreen) delete normalizedScreen.fields;
          if ('list' in normalizedScreen) delete normalizedScreen.list;
          break;
        default:
          // Для остальных шаблонов (info, date, coupon, soulmate) удаляем специфичные поля
          if ('fields' in normalizedScreen) delete normalizedScreen.fields;
          if ('list' in normalizedScreen) delete normalizedScreen.list;
          if ('progressbars' in normalizedScreen) delete normalizedScreen.progressbars;
          break;
      }
      
      // Нормализуем variants - добавляем пустой overrides если его нет
      if ('variants' in normalizedScreen && Array.isArray(normalizedScreen.variants)) {
        normalizedScreen.variants = normalizedScreen.variants.map((variant) => ({
          conditions: variant.conditions || [],
          overrides: variant.overrides || {},
        }));
      }
      
      // Удаляем variables из экранов, которые не поддерживают это поле
      // variables поддерживается только в info экранах
      if ('variables' in normalizedScreen && normalizedScreen.template !== 'info') {
        delete normalizedScreen.variables;
      }
      
      return normalizedScreen;
    }),
  };
}

async function saveFunnelToFile(funnel) {
  const funnelId = funnel.funnelData.meta.id;
  const fileName = `${funnelId}.json`;
  const filePath = path.join(funnelsDir, fileName);
  
  try {
    // Нормализуем данные перед сохранением (удаляем лишние поля)
    const normalizedData = normalizeFunnelData(funnel.funnelData);
    
    // Сохраняем только funnelData (структуру воронки)
    const funnelContent = JSON.stringify(normalizedData, null, 2);
    await fs.writeFile(filePath, funnelContent, 'utf8');
    console.log(`💾 Saved ${fileName} (v${funnel.version})`);
  } catch (error) {
    console.error(`❌ Error saving ${fileName}:`, error.message);
    throw error;
  }
}

async function bakeFunnels() {
  try {
    console.log('🔥 Baking funnels...');
    execSync('npm run bake:funnels', { 
      cwd: projectRoot,
      stdio: 'inherit'
    });
    console.log('✅ Funnels baked successfully');
  } catch (error) {
    console.error('❌ Error baking funnels:', error.message);
    throw error;
  }
}


// Парсим аргументы командной строки
const args = process.argv.slice(2);
const options = {
  funnelIds: [],
  dryRun: false,
  cleanFiles: false, // По умолчанию сохраняем файлы
};

// Парсим опции
for (let i = 0; i < args.length; i++) {
  const arg = args[i];
  
  if (arg === '--dry-run') {
    options.dryRun = true;
  } else if (arg === '--clean-files') {
    options.cleanFiles = true;
  } else if (arg === '--funnel-ids') {
    // Следующий аргумент должен содержать ID воронок через запятую
    const idsArg = args[++i];
    if (idsArg) {
      options.funnelIds = idsArg.split(',').map(id => id.trim());
    }
  } else if (arg === '--help' || arg === '-h') {
    console.log(`
🔄 Sync Funnels from Database

Usage: npm run sync:funnels [options]

Options:
  --dry-run           Show what would be synced without actually doing it
  --clean-files       Delete JSON files after baking (default: keep files)
  --funnel-ids <ids>  Sync only specific funnel IDs (comma-separated)
  --help, -h          Show this help message

Examples:
  npm run sync:funnels                    # Sync all and keep JSON files
  npm run sync:funnels -- --dry-run       # Preview what would be synced
  npm run sync:funnels -- --clean-files   # Sync all and clean up JSON files
  npm run sync:funnels -- --funnel-ids funnel-test,ru-career-accelerator
`);
    process.exit(0);
  }
}

// Обновляем функцию syncFunnels для поддержки опций
async function syncFunnelsWithOptions() {
  if (options.dryRun) {
    console.log('🔍 DRY RUN MODE - No actual changes will be made\n');
  }
  
  console.log('🚀 Starting funnel sync from database...\n');

  try {
    // 1. Подключаемся к базе данных
    await connectDB();

    // 2. Создаем/очищаем папку для воронок (только если не dry-run)
    await ensureFunnelsDir();
    if (!options.dryRun) {
      await clearFunnelsDir();
    }

    // 3. Получаем последние версии всех опубликованных воронок
    const allFunnels = await getLatestPublishedFunnels();
    
    // Фильтруем по указанным ID если они заданы
    let funnels = allFunnels;
    if (options.funnelIds.length > 0) {
      funnels = allFunnels.filter(funnel => 
        options.funnelIds.includes(funnel.funnelData.meta.id)
      );
      console.log(`🎯 Filtering to ${funnels.length} specific funnels: ${options.funnelIds.join(', ')}`);
    }

    if (funnels.length === 0) {
      console.log('ℹ️  No published funnels found matching criteria');
      return;
    }

    // 4. Загружаем изображения из базы данных
    let imageMapping = {};
    if (!options.dryRun) {
      imageMapping = await downloadImagesFromDatabase(funnels);
      if (Object.keys(imageMapping).length > 0) {
        updateImageUrlsInFunnels(funnels, imageMapping);
      }
    } else {
      console.log('🔍 Would download images from database and update URLs');
    }

    // 5. Сохраняем каждую воронку в JSON файл
    for (const funnel of funnels) {
      if (options.dryRun) {
        console.log(`🔍 Would save ${funnel.funnelData.meta.id}.json (v${funnel.version})`);
      } else {
        await saveFunnelToFile(funnel);
      }
    }

    // 6. Запекаем воронки в TypeScript
    if (!options.dryRun) {
      await bakeFunnels();
    } else {
      console.log('🔍 Would bake funnels to TypeScript');
    }

    // 7. Удаляем JSON файлы после запекания (только если указано)
    if (!options.dryRun && options.cleanFiles) {
      await clearFunnelsDir();
      console.log('🧹 Cleaned up JSON files as requested');
    } else if (!options.dryRun) {
      console.log('📁 Keeping JSON files (use --clean-files to remove them)');
    } else if (options.dryRun && options.cleanFiles) {
      console.log('🔍 Would clean up JSON files');
    } else if (options.dryRun) {
      console.log('🔍 Would keep JSON files');
    }

    console.log('\n🎉 Funnel sync completed successfully!');
    console.log(`📈 ${options.dryRun ? 'Would sync' : 'Synced'} ${funnels.length} funnels from database`);

  } catch (error) {
    console.error('\n💥 Sync failed:', error.message);
    process.exit(1);
  } finally {
    await mongoose.disconnect();
    console.log('🔌 Disconnected from MongoDB');
  }
}

// Запускаем скрипт с опциями
syncFunnelsWithOptions();
