const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const moment = require('moment');

// Konfigurasi
const changelogFilePath = path.join(__dirname, '../CHANGELOG.md');
const packageJsonPath = path.join(__dirname, '../package.json');

// Mapping dari gitmoji atau tipe commit ke judul di changelog
// Kunci bisa berupa emoji (untuk gitmoji) atau teks (untuk conventional commits)
const categoryMapping = {
  '✨': '### ✨ Ditambahkan', // :sparkles:
  '🐛': '### 🐛 Diperbaiki', // :bug:
  '⚡️': '### ⚡️ Peningkatan Performa', // :zap:
  '♻️': '### ♻️ Refaktor Kode', // :recycle:
  '📝': '### 📝 Dokumentasi', // :memo:
  '🎨': '### 🎨 Perubahan Struktur/Gaya', // :art:
  '✅': '### ✅ Pengujian', // :white_check_mark:
  '🏗️': '### 🏗️ Perubahan Build System', // :building_construction:
  '🚀': '### 🚀 Perubahan CI/CD', // :rocket:
  '🔧': '### 🔧 Tugas Lain-lain', // :wrench:
  '🔨': '### 🔨 Perbaikan & Pembaruan', // :hammer:
  'chore': '### 🔧 Tugas Lain-lain', // Fallback untuk conventional commit
};

function executeGitCommand(command) {
  try {
    return execSync(command).toString().trim();
  } catch (error) {
    console.error(`Error executing git command: ${command}`, error.stderr.toString());
    return null;
  }
}

function getLatestTag() {
  // Mengambil tag terbaru berdasarkan versi semantik
  return executeGitCommand('git describe --tags --abbrev=0');
}

function getCommitsSinceTag(tag) {
  // Format: <hash>|<author>|<date>|<subject>
  // Mengambil commit dari tag tersebut hingga HEAD (commit terakhir)
  const command = `git log ${tag}..HEAD --pretty=format:"%s"`;
  const commits = executeGitCommand(command);
  return commits ? commits.split('\n').filter(Boolean) : [];
}

function generateChangelog() {
  console.log('Memulai pembuatan changelog...');

  const latestTag = getLatestTag();
  if (!latestTag) {
    console.error('Tidak ada tag yang ditemukan. Buat tag rilis terlebih dahulu, contoh: git tag v1.3.0');
    process.exit(1);
  }
  console.log(`Menganalisis commit sejak tag terakhir: ${latestTag}`);

  const commits = getCommitsSinceTag(latestTag);
  if (commits.length === 0) {
    console.log('Tidak ada commit baru sejak tag terakhir. Tidak ada yang perlu diubah.');
    return;
  }

  const categorizedCommits = {};

  commits.forEach(commitMessage => {
    // Regex diperbarui untuk menangkap:
    // 1. Emoji gitmoji di awal (✨, 🐛, 🔨, dll.)
    // 2. Tipe conventional commit (feat, fix, dll.)
    // 3. Tipe conventional commit yang diapit titik dua (:fix:, :build:, dll.)
    const match = commitMessage.match(/^(✨|🐛|⚡️|♻️|📝|🎨|✅|🏗️|🚀|🔧|🔨)|(:(feat|fix|perf|refactor|docs|style|test|build|ci|chore):)|(^(feat|fix|perf|refactor|docs|style|test|build|ci|chore))/);

    if (match) {
      // Menentukan tipe dari hasil match regex. Prioritaskan emoji, lalu :type:, lalu type.
      const typeOrEmoji = match[1] || match[3] || match[4];
      
      // Hapus prefix dari pesan commit untuk mendapatkan pesan bersih
      let message = commitMessage.replace(match[0], '').trim();

      // Tentukan kategori berdasarkan mapping. Prioritaskan emoji.
      let categoryTitle = categoryMapping[typeOrEmoji];
      if (!categoryTitle) {
          // Fallback jika hanya ada conventional commit type tanpa emoji yang terdaftar
          categoryTitle = categoryMapping['chore'];
      }

      if (!categorizedCommits[categoryTitle]) {
        categorizedCommits[categoryTitle] = [];
      }
      categorizedCommits[categoryTitle].push(`- ${message.charAt(0).toUpperCase() + message.slice(1)}`);
    }
  });

  if (Object.keys(categorizedCommits).length === 0) {
    console.log('Tidak ada commit yang mengikuti standar Conventional Commits. Changelog tidak dibuat.');
    return;
  }

  // Ambil versi dari package.json
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
  const newVersion = packageJson.version;
  const today = moment().format('YYYY-MM-DD');

  let newChangelogContent = `## [${newVersion}] - ${today}\n\n`;

  // Urutkan kategori sesuai urutan di mapping untuk konsistensi
  Object.values(categoryMapping).forEach(categoryTitle => {
    if (categorizedCommits[categoryTitle]) {
      newChangelogContent += `${categoryTitle}\n`;
      newChangelogContent += categorizedCommits[categoryTitle].join('\n') + '\n\n';
    }
  });

  // Baca changelog lama dan tambahkan konten baru di atasnya
  const oldChangelogContent = fs.readFileSync(changelogFilePath, 'utf-8');
  // Hapus header utama agar tidak duplikat
  const oldContentWithoutHeader = oldChangelogContent.split('\n').slice(2).join('\n').trim();

  const finalChangelog = `# Riwayat Perubahan (Changelog)\n\nSemua perubahan penting pada proyek ini akan didokumentasikan di file ini.\n\n${newChangelogContent}${oldContentWithoutHeader}`;

  fs.writeFileSync(changelogFilePath, finalChangelog);

  console.log(`Changelog berhasil diperbarui untuk versi ${newVersion} di file ${changelogFilePath}`);
}

generateChangelog();