const { ModModel, ModAssetModel, ServerModPreferencesModel } = require('../models/ModModels');
const LocalDatabase = require('../config/LocalDatabase');
const logger = require('../utils/logger');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

class ModService {
  constructor() {
    this.modsDirectory = path.join(__dirname, '../../mods');
    this.initialized = false;
  }

  async initialize() {
    try {
      // Initialize local database
      await LocalDatabase.initialize();
      
      // Create mods directory if it doesn't exist
      if (!fs.existsSync(this.modsDirectory)) {
        fs.mkdirSync(this.modsDirectory, { recursive: true });
        logger.info(`[MOD SERVICE] Created mods directory: ${this.modsDirectory}`);
      }
      
      // Load existing mods from filesystem
      await this.loadModsFromFilesystem();
      
      this.initialized = true;
      logger.info('[MOD SERVICE] Mod service initialized successfully');
    } catch (error) {
      logger.error('[MOD SERVICE] Failed to initialize mod service:', error);
      throw error;
    }
  }

  async loadModsFromFilesystem() {
    try {
      if (!fs.existsSync(this.modsDirectory)) {
        return;
      }

      const modFolders = fs.readdirSync(this.modsDirectory, { withFileTypes: true })
        .filter(dirent => dirent.isDirectory())
        .map(dirent => dirent.name);

      for (const modFolder of modFolders) {
        await this.loadModFromFolder(modFolder);
      }

      logger.info(`[MOD SERVICE] Loaded ${modFolders.length} mods from filesystem`);
    } catch (error) {
      logger.error('[MOD SERVICE] Error loading mods from filesystem:', error);
    }
  }

  async loadModFromFolder(modFolder) {
    try {
      const modPath = path.join(this.modsDirectory, modFolder);
      const manifestPath = path.join(modPath, 'mod.json');

      if (!fs.existsSync(manifestPath)) {
        logger.warn(`[MOD SERVICE] Mod ${modFolder} missing mod.json manifest`);
        return;
      }

      const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
      
      // Validate required fields
      if (!manifest.name || !manifest.version || !manifest.author) {
        logger.warn(`[MOD SERVICE] Mod ${modFolder} has invalid manifest`);
        return;
      }

      // Check if mod already exists in database
      const existingMod = await ModModel.findByName(manifest.name);
      
      // Calculate checksum of mod files
      const checksum = await this.calculateModChecksum(modPath);

      const modData = {
        name: manifest.name,
        version: manifest.version,
        author: manifest.author,
        description: manifest.description || '',
        filePath: modPath,
        checksum,
        dependencies: manifest.dependencies || [],
        config: manifest.config || {}
      };

      if (existingMod) {
        // Update existing mod if checksum changed
        if (existingMod.checksum !== checksum) {
          await ModModel.update(existingMod.id, modData);
          logger.info(`[MOD SERVICE] Updated mod: ${manifest.name}`);
        }
      } else {
        // Create new mod
        await ModModel.create(modData);
        logger.info(`[MOD SERVICE] Installed new mod: ${manifest.name}`);
      }

      // Load mod assets
      await this.loadModAssets(manifest.name, modPath);

    } catch (error) {
      logger.error(`[MOD SERVICE] Error loading mod ${modFolder}:`, error);
    }
  }

  async loadModAssets(modName, modPath) {
    try {
      const mod = await ModModel.findByName(modName);
      if (!mod) return;

      // Clear existing assets for this mod
      await ModAssetModel.deleteByModId(mod.id);

      // Load assets from assets folder
      const assetsPath = path.join(modPath, 'assets');
      if (fs.existsSync(assetsPath)) {
        await this.loadAssetsFromDirectory(mod.id, assetsPath);
      }

      logger.info(`[MOD SERVICE] Loaded assets for mod: ${modName}`);
    } catch (error) {
      logger.error(`[MOD SERVICE] Error loading assets for mod ${modName}:`, error);
    }
  }

  async loadAssetsFromDirectory(modId, assetsPath) {
    const assetTypes = ['ships', 'items', 'quests', 'systems'];
    
    for (const assetType of assetTypes) {
      const assetTypePath = path.join(assetsPath, assetType);
      
      if (fs.existsSync(assetTypePath)) {
        const assetFiles = fs.readdirSync(assetTypePath);
        
        for (const assetFile of assetFiles) {
          if (assetFile.endsWith('.json')) {
            try {
              const assetData = JSON.parse(
                fs.readFileSync(path.join(assetTypePath, assetFile), 'utf8')
              );
              
              const assetId = path.basename(assetFile, '.json');
              
              await ModAssetModel.create({
                modId,
                assetType: assetType.slice(0, -1), // Remove 's' for singular
                assetId,
                assetData
              });
            } catch (error) {
              logger.error(`[MOD SERVICE] Error loading asset ${assetFile}:`, error);
            }
          }
        }
      }
    }
  }

  async calculateModChecksum(modPath) {
    try {
      const hash = crypto.createHash('sha256');
      
      // Hash all files in mod directory
      const hashDirectory = (dir) => {
        const files = fs.readdirSync(dir);
        
        files.forEach(file => {
          const filePath = path.join(dir, file);
          const stat = fs.statSync(filePath);
          
          if (stat.isDirectory()) {
            hashDirectory(filePath);
          } else {
            const data = fs.readFileSync(filePath);
            hash.update(data);
          }
        });
      };
      
      hashDirectory(modPath);
      return hash.digest('hex');
    } catch (error) {
      logger.error(`[MOD SERVICE] Error calculating checksum for ${modPath}:`, error);
      return null;
    }
  }

  // Public API methods
  async getMods(enabledOnly = false) {
    return await ModModel.findAll(enabledOnly);
  }

  async getMod(id) {
    return await ModModel.findById(id);
  }

  async getModByName(name) {
    return await ModModel.findByName(name);
  }

  async enableMod(id) {
    const result = await ModModel.enable(id);
    if (result) {
      logger.info(`[MOD SERVICE] Enabled mod: ${id}`);
    }
    return result;
  }

  async disableMod(id) {
    const result = await ModModel.disable(id);
    if (result) {
      logger.info(`[MOD SERVICE] Disabled mod: ${id}`);
    }
    return result;
  }

  async getModAssets(assetType) {
    return await ModAssetModel.findByType(assetType);
  }

  async getModAsset(assetType, assetId) {
    return await ModAssetModel.findByTypeAndId(assetType, assetId);
  }

  async getLoadOrder() {
    return await ModModel.getLoadOrder();
  }

  async setLoadOrder(modIds) {
    const result = await ModModel.setLoadOrder(modIds);
    if (result) {
      logger.info(`[MOD SERVICE] Updated mod load order`);
    }
    return result;
  }

  async getServerPreferences() {
    return await ServerModPreferencesModel.getAll();
  }

  async setServerPreference(key, value) {
    return await ServerModPreferencesModel.set(key, value);
  }

  async reloadMods() {
    logger.info('[MOD SERVICE] Reloading mods from filesystem...');
    await this.loadModsFromFilesystem();
  }

  async shutdown() {
    if (this.initialized) {
      await LocalDatabase.close();
      this.initialized = false;
      logger.info('[MOD SERVICE] Mod service shut down');
    }
  }
}

module.exports = new ModService();
