'use strict';

const { topologicalSort } = require('./topological-sort');
const { getDialect } = require('./dialect');
const { emitCreateTable } = require('./emitters/create-table');
const { emitCreateIndexes } = require('./emitters/create-index');
const { emitDropTable } = require('./emitters/drop-table');

const HEADER_RULE = '-- ============================================================';

/**
 * Generate DDL string untuk semua model dalam map.
 *
 * @param {Map<string, object>} models - output loadSchemaFolder() yang sudah validated
 * @param {object} options
 * @param {string} options.dialect - 'postgres' | 'mysql' | 'oracle' | 'sqlite'
 * @param {boolean} [options.drop=false] - prepend DROP TABLE statements
 * @param {number} [options.maxNameLength] - override identifier length cap (per-call)
 * @returns {string} - SQL output siap pakai
 */
function generateDDL(models, options) {
  if (!(models instanceof Map)) {
    throw new Error('generateDDL: models must be a Map');
  }
  if (!options || typeof options !== 'object') {
    throw new Error('generateDDL: options must be an object');
  }

  const baseDialect = getDialect(options.dialect);
  const drop = options.drop === true;
  const dialect = (typeof options.maxNameLength === 'number' && options.maxNameLength > 0)
    ? Object.assign({}, baseDialect, { maxIdentifierLength: options.maxNameLength })
    : baseDialect;

  const out = [];
  out.push(HEADER_RULE);
  out.push('-- Generated by dbschema:generate-ddl');
  out.push(`-- Dialect: ${dialect.name}`);
  out.push(`-- Generated at: ${new Date().toISOString()}`);
  out.push(HEADER_RULE);

  if (models.size === 0) {
    return out.join('\n') + '\n';
  }

  const order = topologicalSort(models);

  if (drop) {
    out.push('');
    out.push('-- DROP section');
    const dropOrder = order.slice().reverse();
    for (const qualified of dropOrder) {
      const ir = models.get(qualified);
      const stmt = emitDropTable(ir, dialect);
      // Oracle PL/SQL block already terminates with `/`; do not append `;`
      if (dialect.name === 'oracle') {
        out.push(stmt);
      } else {
        out.push(`${stmt};`);
      }
    }
  }

  out.push('');
  out.push('-- CREATE TABLE section');
  for (let i = 0; i < order.length; i++) {
    const qualified = order[i];
    const ir = models.get(qualified);
    const stmt = emitCreateTable(ir, dialect);
    out.push(`${stmt};`);
    if (i < order.length - 1) {
      out.push('');
    }
  }

  const indexStatements = [];
  for (const qualified of order) {
    const ir = models.get(qualified);
    const stmts = emitCreateIndexes(ir, dialect);
    for (const s of stmts) indexStatements.push(`${s};`);
  }

  if (indexStatements.length > 0) {
    out.push('');
    out.push('-- CREATE INDEX section');
    for (const s of indexStatements) out.push(s);
  }

  return out.join('\n') + '\n';
}

module.exports = { generateDDL };
