// HR & Payroll — PT Bumi Niaga (fictional trading & distribusi, Bekasi)
// Periode demo: April 2026 (gaji April akan dirun 25 April)

const TENANT = {
  name: 'PT Bumi Niaga',
  tagline: 'Distribusi Consumer Goods Wilayah Jabodetabek',
  address: 'Kawasan Industri MM2100 Blok H-12, Cibitung, Bekasi 17520',
  npwp: '01.847.291.5-058.000',
  phone: '021-8983-***',
  bpjsTk: 'JK010234567',
  bpjsKes: '0001-23-456789',
};

const TODAY = '2026-04-22';
const PERIODE = '2026-04';
const PERIODE_LABEL = 'April 2026';
const NEXT_PAYROLL = '2026-04-25';

const ROLES = {
  staf:    { name: 'Indra Permana',    role: 'Staf HR' },
  manajer: { name: 'Lidya Hartono',    role: 'Manajer HR' },
  finance: { name: 'Rudi Setiawan',    role: 'Manajer Finance' },
  direksi: { name: 'Bp. Tanto Wibowo', role: 'Direktur Utama' },
};

// Departments
const DEPT = [
  { id: 'OPS',  name: 'Operasional',     headcount: 14, manager: 'Andika Putra' },
  { id: 'SLS',  name: 'Sales & Marketing', headcount: 12, manager: 'Rina Suryani' },
  { id: 'WHS',  name: 'Warehouse',       headcount: 10, manager: 'Bagus Pratama' },
  { id: 'FIN',  name: 'Finance & Accounting', headcount: 5, manager: 'Rudi Setiawan' },
  { id: 'HRD',  name: 'HR & GA',         headcount: 4, manager: 'Lidya Hartono' },
  { id: 'IT',   name: 'IT Support',      headcount: 3, manager: 'Doni Siregar' },
];

// Karyawan (48 employees) — generated mix
const _NAMA_DEPAN_L = ['Adi','Bagas','Candra','Dimas','Eko','Fajar','Galih','Hendra','Indra','Joko','Kurnia','Lukman','Mulyadi','Nanda','Oka','Putra','Rizki','Surya','Tomo','Wahyu','Yoga','Zaki'];
const _NAMA_DEPAN_P = ['Anita','Bunga','Citra','Dewi','Erni','Farah','Gita','Hesti','Indah','Juwita','Kiki','Lila','Maya','Nadia','Oktavia','Putri','Ratna','Sari','Tika','Vina','Wulan','Yuni'];
const _NAMA_BLKG = ['Pratama','Wijaya','Sutanto','Hartono','Setiawan','Lestari','Anggraini','Permadi','Suryani','Saputra','Utomo','Maulana','Kusuma','Adiwijaya','Halim','Pranata','Sihombing','Nugroho','Hidayat','Santosa'];

function _mkKaryawan() {
  const arr = [];
  let id = 1001;
  // Distribute headcount across departments
  for (const d of DEPT) {
    for (let i = 0; i < d.headcount; i++) {
      const isL = ((id + i * 3) % 10) >= 4;
      const depan = isL ? _NAMA_DEPAN_L[(id - 1001 + i) % _NAMA_DEPAN_L.length] : _NAMA_DEPAN_P[(id - 1001 + i) % _NAMA_DEPAN_P.length];
      const blkg = _NAMA_BLKG[(id * 7 + i * 3) % _NAMA_BLKG.length];
      const nama = `${depan} ${blkg}`;
      // Determine role tier within dept
      const tier = i === 0 ? 'Manager' : i < 3 ? 'Supervisor' : i < 6 ? 'Senior Staff' : 'Staff';
      const golMap = { 'Manager': 'IV', 'Supervisor': 'III', 'Senior Staff': 'II', 'Staff': 'I' };
      const baseMap = { 'Manager': 14_000_000, 'Supervisor': 9_500_000, 'Senior Staff': 6_500_000, 'Staff': 4_800_000 };
      const tunjJabMap = { 'Manager': 3_000_000, 'Supervisor': 1_500_000, 'Senior Staff': 800_000, 'Staff': 400_000 };
      arr.push({
        id: 'EMP-' + id,
        nama,
        gender: isL ? 'L' : 'P',
        deptId: d.id,
        dept: d.name,
        jabatan: tier === 'Manager' ? `Manager ${d.name}` : tier === 'Supervisor' ? `Supervisor ${d.name}` : tier,
        golongan: golMap[tier],
        tier,
        statusKerja: i % 17 === 5 ? 'Kontrak' : 'Tetap',
        masuk: 2017 + ((id * 3) % 9) + '-' + String(((id * 11) % 12) + 1).padStart(2,'0') + '-' + String(((id * 7) % 28) + 1).padStart(2,'0'),
        statusKawin: i % 3 === 0 ? 'TK/0' : i % 3 === 1 ? 'K/1' : 'K/2',
        npwp: i % 4 === 3 ? null : `0${(8 + (id % 9))}.${(100 + (id * 13) % 900).toString()}.${((id * 17) % 900 + 100)}.${((id * 23) % 900 + 100)}-${((id * 29) % 900 + 100)}.000`,
        bpjsTk: `JK${(id * 7 + 1000000).toString().slice(0,7)}`,
        bpjsKes: `${id}-${(id * 13).toString().slice(0,2)}-${(id * 19).toString().slice(0,6)}`,
        norek: `0${(7140 + id)} ${(id * 3 + 100000).toString().slice(0,6)}`,
        bank: ['BCA','Mandiri','BRI','BNI'][id % 4],
        gajiPokok: baseMap[tier],
        tunjJabatan: tunjJabMap[tier],
        tunjTransport: tier === 'Manager' ? 1_500_000 : tier === 'Supervisor' ? 1_000_000 : 600_000,
        tunjMakan: 750_000,
      });
      id++;
    }
  }
  return arr;
}

const KARYAWAN = _mkKaryawan();
const KARYAWAN_BY_ID = Object.fromEntries(KARYAWAN.map(k => [k.id, k]));

// Absensi periode April (sample: 22 hari kerja, 1-22 April; weekend skip)
const HARI_KERJA_APRIL = (() => {
  const arr = [];
  for (let d = 1; d <= 22; d++) {
    const date = new Date(2026, 3, d);
    if (date.getDay() === 0 || date.getDay() === 6) continue;
    arr.push(`2026-04-${String(d).padStart(2, '0')}`);
  }
  return arr;
})();

// Generate absensi summary per karyawan
const ABSENSI = KARYAWAN.map((k, idx) => {
  const total = HARI_KERJA_APRIL.length;
  const sakit = idx % 17 === 3 ? 2 : idx % 23 === 5 ? 1 : 0;
  const cuti = idx % 13 === 7 ? 3 : idx % 19 === 11 ? 1 : 0;
  const izin = idx % 31 === 9 ? 1 : 0;
  const alpha = idx % 41 === 7 ? 1 : 0;
  const telat = (idx * 7) % 11 === 3 ? 4 : (idx * 7) % 11 === 6 ? 2 : 0;
  const hadir = total - sakit - cuti - izin - alpha;
  const lemburJam = idx % 9 === 2 ? 12 : idx % 9 === 5 ? 6 : idx % 9 === 7 ? 4 : 0;
  return {
    karyawanId: k.id,
    hadir, sakit, cuti, izin, alpha, telat, lemburJam,
    total,
  };
});

const ABSENSI_BY_ID = Object.fromEntries(ABSENSI.map(a => [a.karyawanId, a]));

// Absensi hari ini (sample 8 entries for live view)
const ABSENSI_HARI_INI = [
  { karyawanId: 'EMP-1001', clockIn: '07:42', clockOut: null, status: 'masuk' },
  { karyawanId: 'EMP-1002', clockIn: '07:55', clockOut: null, status: 'masuk' },
  { karyawanId: 'EMP-1003', clockIn: '08:08', clockOut: null, status: 'telat' },
  { karyawanId: 'EMP-1015', clockIn: '07:38', clockOut: null, status: 'masuk' },
  { karyawanId: 'EMP-1023', clockIn: null,    clockOut: null, status: 'sakit',  keterangan: 'Surat dokter dilampirkan' },
  { karyawanId: 'EMP-1031', clockIn: null,    clockOut: null, status: 'cuti',   keterangan: 'Cuti tahunan hari ke-2 dari 3' },
  { karyawanId: 'EMP-1042', clockIn: '07:47', clockOut: null, status: 'masuk' },
  { karyawanId: 'EMP-1048', clockIn: '08:15', clockOut: null, status: 'telat' },
];

// Cuti requests pending
const CUTI_REQUESTS = [
  { id: 'C-2026-0042', karyawanId: 'EMP-1008', tipe: 'Cuti Tahunan', mulai: '2026-05-04', selesai: '2026-05-08', durasi: 5, sisa: 12, status: 'pending', alasan: 'Liburan keluarga ke Bali', diajukan: '2026-04-20' },
  { id: 'C-2026-0041', karyawanId: 'EMP-1019', tipe: 'Cuti Sakit',  mulai: '2026-04-23', selesai: '2026-04-24', durasi: 2, sisa: 10, status: 'pending', alasan: 'Kontrol post operasi', diajukan: '2026-04-21' },
  { id: 'C-2026-0040', karyawanId: 'EMP-1027', tipe: 'Cuti Tahunan', mulai: '2026-04-28', selesai: '2026-04-30', durasi: 3, sisa:  8, status: 'pending', alasan: 'Acara keluarga di kampung', diajukan: '2026-04-19' },
  { id: 'C-2026-0039', karyawanId: 'EMP-1011', tipe: 'Cuti Menikah', mulai: '2026-05-15', selesai: '2026-05-17', durasi: 3, sisa: 12, status: 'pending', alasan: 'Pernikahan', diajukan: '2026-04-18' },
];

// Lembur recent
const LEMBUR_RECENT = [
  { id: 'L-2026-0218', karyawanId: 'EMP-1003', tanggal: '2026-04-21', jamMulai: '17:00', jamSelesai: '20:00', durasi: 3, alasan: 'Closing bulan unit Sales',     status: 'approved' },
  { id: 'L-2026-0217', karyawanId: 'EMP-1015', tanggal: '2026-04-21', jamMulai: '17:00', jamSelesai: '21:30', durasi: 4.5, alasan: 'Stock opname akhir bulan',     status: 'approved' },
  { id: 'L-2026-0216', karyawanId: 'EMP-1023', tanggal: '2026-04-20', jamMulai: '17:00', jamSelesai: '19:00', durasi: 2, alasan: 'Pengiriman urgent ke retailer', status: 'approved' },
  { id: 'L-2026-0215', karyawanId: 'EMP-1042', tanggal: '2026-04-19', jamMulai: '17:00', jamSelesai: '22:00', durasi: 5, alasan: 'Migrasi server payroll',        status: 'approved' },
];

// Slip gaji generator
function slipGaji(karyawanId, periode = PERIODE) {
  const k = KARYAWAN_BY_ID[karyawanId];
  if (!k) return null;
  const a = ABSENSI_BY_ID[karyawanId] || { hadir: 22, telat: 0, alpha: 0, lemburJam: 0 };

  // Penghasilan
  const gajiPokok = k.gajiPokok;
  const tunjJab = k.tunjJabatan;
  const tunjTrans = k.tunjTransport;
  const tunjMakan = k.tunjMakan;
  const lembur = a.lemburJam * (k.gajiPokok / 173) * 1.5;
  const insentif = k.tier === 'Manager' ? 2_000_000 : k.tier === 'Supervisor' ? 1_000_000 : 0;
  const totalPenghasilan = gajiPokok + tunjJab + tunjTrans + tunjMakan + Math.round(lembur) + insentif;

  // Potongan
  const bpjsKes = Math.round(gajiPokok * 0.01);   // 1%
  const bpjsJht = Math.round(gajiPokok * 0.02);   // 2%
  const bpjsJp  = Math.round(gajiPokok * 0.01);   // 1%
  // PPh 21 sederhana (estimasi 5% dari taxable)
  const taxable = totalPenghasilan - bpjsKes - bpjsJht - bpjsJp;
  const pph21 = k.statusKawin === 'TK/0'
    ? Math.max(0, Math.round((taxable - 4_500_000) * 0.05))
    : k.statusKawin === 'K/1'
    ? Math.max(0, Math.round((taxable - 5_250_000) * 0.05))
    : Math.max(0, Math.round((taxable - 6_000_000) * 0.05));
  const pinjaman = (parseInt(k.id.slice(4)) % 23) === 7 ? 500_000 : 0;
  const totalPotongan = bpjsKes + bpjsJht + bpjsJp + pph21 + pinjaman;

  const takeHome = totalPenghasilan - totalPotongan;

  return {
    karyawan: k,
    periode,
    absensi: a,
    penghasilan: { gajiPokok, tunjJab, tunjTrans, tunjMakan, lembur: Math.round(lembur), insentif, total: totalPenghasilan },
    potongan: { bpjsKes, bpjsJht, bpjsJp, pph21, pinjaman, total: totalPotongan },
    takeHome,
  };
}

// Payroll runs history
const PAYROLL_RUNS = [
  { id: 'PR-2026-04', periode: '2026-04', label: 'April 2026',     status: 'draft',     karyawan: 48, total: null,                runDate: null,         processedBy: null,   summary: 'Draft — akan dijalankan 25 April' },
  { id: 'PR-2026-03', periode: '2026-03', label: 'Maret 2026',     status: 'paid',      karyawan: 47, total: 412_580_000,         runDate: '2026-03-25', processedBy: 'Lidya', summary: 'Paid via Mandiri Cash Management' },
  { id: 'PR-2026-02', periode: '2026-02', label: 'Februari 2026',  status: 'paid',      karyawan: 46, total: 398_240_000,         runDate: '2026-02-25', processedBy: 'Lidya', summary: 'Paid (THR belum dirilis)' },
  { id: 'PR-2026-01', periode: '2026-01', label: 'Januari 2026',   status: 'paid',      karyawan: 46, total: 401_120_000,         runDate: '2026-01-25', processedBy: 'Lidya', summary: 'Bonus tahunan dirilis terpisah' },
  { id: 'PR-2025-12', periode: '2025-12', label: 'Desember 2025',  status: 'paid',      karyawan: 45, total: 612_440_000,         runDate: '2025-12-22', processedBy: 'Lidya', summary: 'Termasuk THR & bonus tahunan' },
];

// Project payroll April (estimasi)
const _allSlips = KARYAWAN.map(k => slipGaji(k.id));
PAYROLL_RUNS[0].total = _allSlips.reduce((s, sl) => s + sl.takeHome, 0);
PAYROLL_RUNS[0].totalPenghasilan = _allSlips.reduce((s, sl) => s + sl.penghasilan.total, 0);
PAYROLL_RUNS[0].totalPotongan = _allSlips.reduce((s, sl) => s + sl.potongan.total, 0);

// KPI
const KPI = {
  totalKaryawan: KARYAWAN.length,
  hadirHariIni: ABSENSI_HARI_INI.filter(a => a.status === 'masuk' || a.status === 'telat').length,
  cutiHariIni:  ABSENSI_HARI_INI.filter(a => a.status === 'cuti').length,
  sakitHariIni: ABSENSI_HARI_INI.filter(a => a.status === 'sakit').length,
  telatHariIni: ABSENSI_HARI_INI.filter(a => a.status === 'telat').length,
  pendingCuti:  CUTI_REQUESTS.filter(c => c.status === 'pending').length,
  payrollDraft: PAYROLL_RUNS[0].total,
  payrollKaryawan: PAYROLL_RUNS[0].karyawan,
};

// Activity log
const ACTIVITY = [
  { id: 1, time: '08:15', text: 'Vina Lestari (EMP-1048) clock-in 08:15 — terlambat 15 menit', who: 'Sistem Absensi', urgent: false },
  { id: 2, time: '08:08', text: 'Candra Pratama (EMP-1003) clock-in 08:08 — terlambat 8 menit', who: 'Sistem Absensi', urgent: false },
  { id: 3, time: '07:55', text: 'Pengajuan cuti Joko Setiawan (EMP-1008) menunggu approval', who: 'Indra (HR)', urgent: true },
  { id: 4, time: '07:30', text: 'Reminder: payroll April akan dijalankan 25 April (3 hari lagi)', who: 'Sistem', urgent: true },
  { id: 5, time: '07:00', text: '6 karyawan sudah clock-in (3 di kantor pusat, 3 di gudang)', who: 'Sistem Absensi', urgent: false },
  { id: 6, time: 'Kemarin', text: 'Data lembur stock opname (5 karyawan) di-input ke payroll', who: 'Lidya (Manajer HR)', urgent: false },
  { id: 7, time: '20 Apr', text: 'Pengajuan cuti tahunan Joko Setiawan (5 hari, 4-8 Mei) diterima', who: 'Indra (HR)', urgent: false },
];

// Cost breakdown for laporan
const COST_BREAKDOWN_DEPT = DEPT.map(d => {
  const employees = KARYAWAN.filter(k => k.deptId === d.id);
  const totalGaji = employees.reduce((s, k) => s + slipGaji(k.id).takeHome, 0);
  return { dept: d.name, deptId: d.id, headcount: employees.length, total: totalGaji };
}).sort((a, b) => b.total - a.total);

// Helpers
function rupiah(n, opts = {}) {
  const { sym = false, compact = false } = opts;
  if (n == null || isNaN(n)) return '—';
  let s;
  if (compact && Math.abs(n) >= 1_000_000_000) s = (n / 1_000_000_000).toFixed(n % 1_000_000_000 ? 2 : 0).replace('.', ',') + ' M';
  else if (compact && Math.abs(n) >= 1_000_000) s = (n / 1_000_000).toFixed(n % 1_000_000 ? 1 : 0).replace('.', ',') + ' jt';
  else if (compact && Math.abs(n) >= 1_000) s = (n / 1_000).toFixed(0).replace('.', ',') + ' rb';
  else s = Math.abs(n).toLocaleString('id-ID');
  return (sym ? 'Rp ' : '') + (n < 0 ? '−' : '') + s;
}

function formatDateID(iso) {
  const d = new Date(iso + 'T00:00:00');
  const days = ['Min','Sen','Sel','Rab','Kam','Jum','Sab'];
  const months = ['Jan','Feb','Mar','Apr','Mei','Jun','Jul','Agu','Sep','Okt','Nov','Des'];
  return `${days[d.getDay()]}, ${d.getDate()} ${months[d.getMonth()]} ${d.getFullYear()}`;
}

function initials(name) {
  return name.split(' ').filter(w => w.length > 1).slice(0, 2).map(w => w[0]).join('').toUpperCase();
}

function statusTone(s) {
  return s === 'masuk' ? 'success'
    : s === 'telat' ? 'warn'
    : s === 'sakit' ? 'accent'
    : s === 'cuti'  ? 'accent'
    : s === 'alpha' ? 'danger'
    : s === 'pending'   ? 'warn'
    : s === 'approved'  ? 'success'
    : s === 'paid'      ? 'success'
    : s === 'draft'     ? 'warn'
    : s === 'rejected'  ? 'danger'
    : 'muted';
}

function statusLabel(s) {
  return s === 'masuk' ? 'Hadir'
    : s === 'telat' ? 'Telat'
    : s === 'sakit' ? 'Sakit'
    : s === 'cuti'  ? 'Cuti'
    : s === 'alpha' ? 'Alpha'
    : s === 'pending'  ? 'Menunggu'
    : s === 'approved' ? 'Disetujui'
    : s === 'paid'     ? 'Dibayar'
    : s === 'draft'    ? 'Draft'
    : s === 'rejected' ? 'Ditolak'
    : s;
}

function formatTanggalKerja(iso) {
  const d = new Date(iso + 'T00:00:00');
  return d.getDate() + ' ' + ['Jan','Feb','Mar','Apr','Mei','Jun','Jul','Agu','Sep','Okt','Nov','Des'][d.getMonth()];
}

Object.assign(window, {
  TENANT, TODAY, PERIODE, PERIODE_LABEL, NEXT_PAYROLL, ROLES,
  DEPT, KARYAWAN, KARYAWAN_BY_ID,
  HARI_KERJA_APRIL, ABSENSI, ABSENSI_BY_ID, ABSENSI_HARI_INI,
  CUTI_REQUESTS, LEMBUR_RECENT, PAYROLL_RUNS, KPI, ACTIVITY,
  COST_BREAKDOWN_DEPT,
  slipGaji, rupiah, formatDateID, formatTanggalKerja, initials,
  statusTone, statusLabel,
});
