const fs = require('fs');
const path = require('path');
const ConfigReader = require('../config/config-reader');
const FileUtils = require('../utils/file-utils');

/**
 * Generator untuk model files
 */
class ModelGenerator {

  /**
   * Generate model file
   * @param {string} moduleName - Nama module
   * @param {string} endpointName - Nama endpoint
   * @param {Object} processedPayload - Processed payload object
   * @param {boolean} forceOverwrite - Apakah menimpa file yang sudah ada
   * @param {string} databaseType - Tipe database
   * @returns {boolean} True jika berhasil
   */
  static createModelFile(moduleName, endpointName, processedPayload, forceOverwrite = false, databaseType = 'postgres') {
    try {
      console.log(``);
      console.log(`Generating model: ${moduleName}/${endpointName} (${databaseType})`);

      // Setup directories
      const modelsDir = path.join(ConfigReader.getWorkingDirectory(), 'src', 'models', moduleName);
      FileUtils.ensureDirectoryExists(modelsDir);

      const modelFilePath = path.join(modelsDir, `${endpointName}.js`);

      // Check if file exists
      if (fs.existsSync(modelFilePath) && !forceOverwrite) {
        console.log(`Model ${endpointName}.js already exists. Use --force=true to overwrite.`);
        return false;
      }

      // Note: SQL file references di-expand inline ke output model oleh PayloadProcessor.processFileReferences

      // Generate model content
      const modelContent = this.generateModelContent(moduleName, endpointName, processedPayload, databaseType);

      // Write model file tanpa backup (archive system digunakan sebagai gantinya)
      FileUtils.writeFileWithBackup(modelFilePath, modelContent, false);

      console.log(`Model ${endpointName}.js generated successfully`);
      return true;

    } catch (error) {
      console.error(`Error generating model ${moduleName}/${endpointName}:`, error.message);
      throw error;
    }
  }

  /**
   * Generate model content based on database type
   * @param {string} moduleName - Nama module
   * @param {string} endpointName - Nama endpoint
   * @param {Object} payload - Processed payload object
   * @param {string} databaseType - Tipe database
   * @returns {string} Generated model content
   */
  static generateModelContent(moduleName, endpointName, payload, databaseType) {
    try {
      // Try Oracle template first if specified
      if (databaseType === 'sqlite') {
        const sqliteContent = this.generateSqliteModelContent(moduleName, endpointName, payload);
        if (sqliteContent) {
          console.log(`Using SQLite-specific template for ${endpointName} model`);
          return sqliteContent;
        } else {
          console.log(`SQLite template not available, falling back to PostgreSQL template`);
        }
      }

      if (databaseType === 'mysql') {
        const mysqlContent = this.generateMysqlModelContent(moduleName, endpointName, payload);
        if (mysqlContent) {
          console.log(`Using MySQL-specific template for ${endpointName} model`);
          return mysqlContent;
        } else {
          console.log(`MySQL template not available, falling back to PostgreSQL template`);
        }
      }

      if (databaseType === 'oracle') {
        const oracleContent = this.generateOracleModelContent(moduleName, endpointName, payload);
        if (oracleContent) {
          console.log(`Using Oracle-specific template for ${endpointName} model`);
          return oracleContent;
        } else {
          console.log(`Oracle template not available, falling back to PostgreSQL template`);
        }
      }

      // Default PostgreSQL template
      return this.generatePostgresModelContent(moduleName, endpointName, payload);

    } catch (error) {
      console.error(`Error generating model content: ${error.message}`);
      throw error;
    }
  }

  /**
   * Generate Oracle model content
   * @param {string} moduleName - Nama module
   * @param {string} endpointName - Nama endpoint
   * @param {Object} payload - Processed payload object
   * @returns {string|null} Oracle model content atau null
   */
  static generateOracleModelContent(moduleName, endpointName, payload) {
    try {
      const oracleUtils = this.loadOracleUtils();
      if (oracleUtils && oracleUtils.createOracleModelTemplate) {
        const content = oracleUtils.createOracleModelTemplate(moduleName, endpointName, payload);
        if (content && content.trim().length > 0) {
          return content;
        }
      }
      return null;
    } catch (error) {
      console.warn(`Oracle model template not available: ${error.message}`);
      return null;
    }
  }

  /**
   * Load Oracle utilities
   * @returns {Object|null} Oracle utils object atau null
   */
  static loadOracleUtils() {
    try {
      return require('../templates/oracle-template');
    } catch (error) {
      return null;
    }
  }

  /**
   * Generate SQLite model content
   * @param {string} moduleName - Nama module
   * @param {string} endpointName - Nama endpoint
   * @param {Object} payload - Processed payload object
   * @returns {string|null} SQLite model content atau null
   */
  static generateSqliteModelContent(moduleName, endpointName, payload) {
    try {
      const sqliteUtils = this.loadSqliteUtils();
      if (sqliteUtils && sqliteUtils.createSqliteModelTemplate) {
        const content = sqliteUtils.createSqliteModelTemplate(moduleName, endpointName, payload);
        if (content && content.trim().length > 0) {
          return content;
        }
      }
      return null;
    } catch (error) {
      console.warn(`SQLite model template not available: ${error.message}`);
      return null;
    }
  }

  /**
   * Load SQLite utilities
   * @returns {Object|null} SQLite utils object atau null
   */
  static loadSqliteUtils() {
    try {
      return require('../templates/sqlite-template');
    } catch (error) {
      return null;
    }
  }

  /**
   * Generate MySQL model content
   * @param {string} moduleName - Nama module
   * @param {string} endpointName - Nama endpoint
   * @param {Object} payload - Processed payload object
   * @returns {string|null} MySQL model content atau null
   */
  static generateMysqlModelContent(moduleName, endpointName, payload) {
    try {
      const mysqlUtils = this.loadMysqlUtils();
      if (mysqlUtils && mysqlUtils.createMysqlModelTemplate) {
        const content = mysqlUtils.createMysqlModelTemplate(moduleName, endpointName, payload);
        if (content && content.trim().length > 0) {
          return content;
        }
      }
      return null;
    } catch (error) {
      console.warn(`MySQL model template not available: ${error.message}`);
      return null;
    }
  }

  /**
   * Load MySQL utilities
   * @returns {Object|null} MySQL utils object atau null
   */
  static loadMysqlUtils() {
    try {
      return require('../templates/mysql-template');
    } catch (error) {
      return null;
    }
  }

  /**
   * Load PostgreSQL utilities
   * @returns {Object|null} PostgreSQL utils object atau null
   */
  static loadPostgresUtils() {
    try {
      return require('../templates/postgres-template');
    } catch (error) {
      return null;
    }
  }

  /**
   * Generate PostgreSQL model content
   * @param {string} moduleName - Nama module
   * @param {string} endpointName - Nama endpoint
   * @param {Object} payload - Processed payload object
   * @returns {string|null} PostgreSQL model content atau null
   */
  static generatePostgresModelContent(moduleName, endpointName, payload) {
    try {
      const postgresUtils = this.loadPostgresUtils();
      if (postgresUtils && postgresUtils.createPostgresModelTemplate) {
        const content = postgresUtils.createPostgresModelTemplate(moduleName, endpointName, payload);
        if (content && content.trim().length > 0) {
          return content;
        }
      }
      return null;
    } catch (error) {
      console.warn(`PostgreSQL model template not available: ${error.message}`);
      return null;
    }
  }

  /**
   * Get generation summary untuk model
   * @param {string} moduleName - Nama module
   * @param {string} endpointName - Nama endpoint
   * @returns {Object} Generation summary
   */
  static getGenerationSummary(moduleName, endpointName) {
    const workingDir = ConfigReader.getWorkingDirectory();
    const modelFilePath = path.join(workingDir, 'src', 'models', moduleName, `${endpointName}.js`);

    return {
      moduleName: moduleName,
      endpointName: endpointName,
      filePath: modelFilePath,
      exists: fs.existsSync(modelFilePath),
      fileInfo: fs.existsSync(modelFilePath) ? FileUtils.getFileInfo(modelFilePath) : null,
      relativePath: path.relative(workingDir, modelFilePath)
    };
  }

  /**
   * Validate model generation options
   * @param {Object} options - Generation options
   * @returns {Object} Validated options
   */
  static validateModelOptions(options = {}) {
    return {
      forceOverwrite: Boolean(options.forceOverwrite || options.force),
      createBackup: options.createBackup !== false,
      includeValidation: options.includeValidation !== false,
      includeAdvancedQueries: options.includeAdvancedQueries !== false,
      ...options
    };
  }

  /**
   * Generate model dengan comprehensive result
   * @param {string} moduleName - Nama module
   * @param {string} endpointName - Nama endpoint
   * @param {Object} processedPayload - Processed payload object
   * @param {boolean} forceOverwrite - Force overwrite
   * @param {string} databaseType - Database type
   * @returns {Object} Generation result
   */
  static generateModelWithResult(moduleName, endpointName, processedPayload, forceOverwrite = false, databaseType = 'postgres') {
    const result = {
      success: false,
      moduleName: moduleName,
      endpointName: endpointName,
      databaseType: databaseType,
      filePath: null,
      backupCreated: false,
      sqlFilesCopied: 0,
      warnings: [],
      errors: []
    };

    try {
      const generated = this.createModelFile(moduleName, endpointName, processedPayload, forceOverwrite, databaseType);

      if (generated) {
        result.success = true;
        const summary = this.getGenerationSummary(moduleName, endpointName);
        result.filePath = summary.filePath;
        result.backupCreated = forceOverwrite && summary.exists;
      }

    } catch (error) {
      result.errors.push(error.message);
      console.error(`Model generation failed: ${error.message}`);
    }

    return result;
  }
}

module.exports = ModelGenerator;
