// AR Collection — CV Sinar Distribusi Nusantara (fictional FMCG distributor)
// Periode demo: April 2026

const TENANT = {
  name: 'CV Sinar Distribusi Nusantara',
  tagline: 'Distributor FMCG Jabodetabek · Term 7/14/30 hari',
  address: 'Jl. Raya Narogong KM 12, Bekasi 17116',
  npwp: '02.918.407.6-432.000',
  phone: '021-8269-***',
};

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

const ROLES = {
  ar:       { name: 'Nabila Putri',    role: 'AR Admin' },
  collector:{ name: 'Rangga Saputra', role: 'Field Collector' },
  finance: { name: 'Teguh Pranata',   role: 'Finance Manager' },
  owner:   { name: 'Hendra Wijaya',   role: 'Owner' },
};

const COLLECTORS = [
  { id:'C01', name:'Rangga Saputra', area:'Bekasi Timur', target:180_000_000 },
  { id:'C02', name:'Maya Lestari',   area:'Jakarta Timur', target:165_000_000 },
  { id:'C03', name:'Arif Maulana',   area:'Depok & Bogor', target:145_000_000 },
  { id:'C04', name:'Sinta Rahma',    area:'Tangerang', target:130_000_000 },
];

const AREAS = ['Bekasi Timur','Jakarta Timur','Depok','Bogor','Tangerang','Cikarang'];
const STORE_NAMES = ['Toko Berkah Jaya','Sumber Rezeki Mart','Warung Makmur','Toko Mitra Sejati','UD Cahaya Pagi','Agen Maju Lancar','Toko Sari Rasa','Minimarket Keluarga','Toko Harapan Baru','Agen Freshindo','Toko Sentosa','UD Bintang Timur','Toko Pojok Murah','Agen Laris Manis','Toko Sejahtera','Warung Ibu Santi','Toko Putra Mandiri','Agen Karya Baru'];

const CUSTOMERS = STORE_NAMES.map((name, i) => {
  const area = AREAS[i % AREAS.length];
  const collector = COLLECTORS[i % COLLECTORS.length];
  const term = [7, 14, 30, 14, 21, 30][i % 6];
  const creditLimit = [15_000_000, 25_000_000, 35_000_000, 50_000_000, 75_000_000][i % 5];
  return {
    id: 'CUS-' + String(2401 + i).padStart(4, '0'),
    name,
    owner: ['Pak Dedi','Ibu Lina','Pak Hasan','Ibu Maya','Pak Rudi','Ibu Wati'][i % 6],
    area,
    collectorId: collector.id,
    term,
    creditLimit,
    phone: `08${12 + (i % 7)}***${(552 + i * 31).toString().slice(-3)}`,
    risk: i % 9 === 2 ? 'high' : i % 5 === 1 ? 'medium' : 'low',
    avgPayDays: term + [0,2,4,7,11,18][i % 6],
    lastOrder: `2026-04-${String(3 + (i % 16)).padStart(2,'0')}`,
  };
});
const CUSTOMER_BY_ID = Object.fromEntries(CUSTOMERS.map(c => [c.id, c]));

function makeInvoice(no, customerId, issue, due, amount, paid = 0, status = 'open', dispute = null) {
  return { id:'INV-2026-' + String(no).padStart(4,'0'), customerId, issueDate:issue, dueDate:due, amount, paid, status, dispute };
}

const INVOICES = [
  makeInvoice(1181,'CUS-2401','2026-04-19','2026-05-03',14_850_000,0,'open'),
  makeInvoice(1180,'CUS-2402','2026-04-17','2026-05-01',22_400_000,0,'open'),
  makeInvoice(1179,'CUS-2403','2026-04-15','2026-04-29',18_750_000,0,'open'),
  makeInvoice(1178,'CUS-2404','2026-04-10','2026-04-24',33_200_000,0,'open'),
  makeInvoice(1177,'CUS-2405','2026-04-08','2026-04-22',41_600_000,0,'due'),
  makeInvoice(1176,'CUS-2406','2026-04-05','2026-04-19',29_300_000,10_000_000,'partial'),
  makeInvoice(1175,'CUS-2407','2026-04-03','2026-04-17',16_900_000,0,'overdue'),
  makeInvoice(1174,'CUS-2408','2026-03-31','2026-04-14',48_500_000,0,'overdue','Selisih harga promo'),
  makeInvoice(1173,'CUS-2409','2026-03-28','2026-04-11',12_250_000,0,'overdue'),
  makeInvoice(1172,'CUS-2410','2026-03-25','2026-04-08',36_800_000,8_000_000,'partial'),
  makeInvoice(1171,'CUS-2411','2026-03-20','2026-04-03',28_700_000,0,'overdue'),
  makeInvoice(1170,'CUS-2412','2026-03-15','2026-03-29',19_400_000,0,'overdue'),
  makeInvoice(1169,'CUS-2413','2026-03-09','2026-03-23',52_200_000,0,'overdue','Retur belum dipotong'),
  makeInvoice(1168,'CUS-2414','2026-03-04','2026-03-18',31_650_000,5_000_000,'partial'),
  makeInvoice(1167,'CUS-2415','2026-02-28','2026-03-14',44_900_000,0,'overdue'),
  makeInvoice(1166,'CUS-2416','2026-02-21','2026-03-07',17_300_000,0,'overdue'),
  makeInvoice(1165,'CUS-2417','2026-02-12','2026-02-26',24_750_000,0,'overdue','Toko klaim barang rusak'),
  makeInvoice(1164,'CUS-2418','2026-01-31','2026-02-14',63_500_000,20_000_000,'partial'),
  makeInvoice(1163,'CUS-2402','2026-01-18','2026-02-01',38_250_000,0,'overdue'),
  makeInvoice(1162,'CUS-2407','2025-12-29','2026-01-12',26_000_000,0,'overdue'),
  makeInvoice(1161,'CUS-2412','2025-12-20','2026-01-03',21_800_000,0,'overdue'),
  makeInvoice(1160,'CUS-2415','2025-11-28','2025-12-12',15_600_000,0,'overdue'),
];

function daysLate(inv) {
  const due = new Date(inv.dueDate + 'T00:00:00');
  const today = new Date(TODAY + 'T00:00:00');
  return Math.floor((today - due) / 86400000);
}
function invoiceBalance(inv) { return inv.amount - inv.paid; }
function agingBucket(inv) {
  const d = daysLate(inv);
  if (d <= 0) return 'current';
  if (d <= 7) return 'd1';
  if (d <= 30) return 'd8';
  if (d <= 60) return 'd31';
  return 'd60';
}

const FOLLOWUPS = [
  { id:'FU-091', invoiceId:'INV-2026-1162', at:'2026-04-22 10:12', channel:'WhatsApp', collectorId:'C03', type:'reminder', note:'Reminder final: invoice 100+ hari. Owner janji cek transfer sore ini.', promiseDate:'2026-04-22', promiseAmount:10_000_000 },
  { id:'FU-090', invoiceId:'INV-2026-1164', at:'2026-04-22 09:40', channel:'Call', collectorId:'C02', type:'promise', note:'Ibu pemilik minta split payment dua kali.', promiseDate:'2026-04-25', promiseAmount:25_000_000 },
  { id:'FU-089', invoiceId:'INV-2026-1169', at:'2026-04-21 16:20', channel:'WhatsApp', collectorId:'C01', type:'dispute', note:'Retur 6 karton belum dibuat CN; tahan pembayaran sampai koreksi.', promiseDate:null, promiseAmount:0 },
  { id:'FU-088', invoiceId:'INV-2026-1174', at:'2026-04-21 13:15', channel:'Visit', collectorId:'C04', type:'dispute', note:'Selisih harga promo Maret Rp 1,2jt, perlu approval sales.', promiseDate:null, promiseAmount:0 },
  { id:'FU-087', invoiceId:'INV-2026-1171', at:'2026-04-21 11:00', channel:'WhatsApp', collectorId:'C03', type:'reminder', note:'Reminder H+18, bukti tagihan dikirim ulang.', promiseDate:'2026-04-24', promiseAmount:28_700_000 },
];

const PAYMENTS = [
  { id:'PAY-2026-0348', customerId:'CUS-2406', invoiceId:'INV-2026-1176', date:'2026-04-22', amount:10_000_000, method:'Transfer BCA', status:'matched', proof:'bca-1176.jpg' },
  { id:'PAY-2026-0347', customerId:'CUS-2410', invoiceId:'INV-2026-1172', date:'2026-04-20', amount:8_000_000, method:'Transfer Mandiri', status:'matched', proof:'mandiri-1172.jpg' },
  { id:'PAY-2026-0346', customerId:'CUS-2418', invoiceId:'INV-2026-1164', date:'2026-04-18', amount:20_000_000, method:'Giro', status:'pending', proof:'giro-1164.pdf' },
  { id:'PAY-2026-0345', customerId:'CUS-2401', invoiceId:null, date:'2026-04-22', amount:7_500_000, method:'Transfer BRI', status:'unmatched', proof:'bri-unknown.jpg' },
];

const TASKS = INVOICES.filter(inv => agingBucket(inv) !== 'current').map((inv, i) => {
  const c = CUSTOMER_BY_ID[inv.customerId];
  const late = daysLate(inv);
  return {
    id:'TASK-' + String(800 + i),
    invoiceId:inv.id,
    customerId:c.id,
    collectorId:c.collectorId,
    stage: inv.dispute ? 'dispute' : late > 60 ? 'visit' : late > 14 ? 'promise' : 'reminder',
    priority: late > 60 || invoiceBalance(inv) > 40_000_000 ? 'high' : late > 14 ? 'medium' : 'normal',
    dueToday: i % 3 !== 0,
  };
});

const COLLECTION_TARGET = COLLECTORS.map(col => {
  const invoices = INVOICES.filter(inv => CUSTOMER_BY_ID[inv.customerId].collectorId === col.id);
  const collected = PAYMENTS.filter(p => CUSTOMER_BY_ID[p.customerId]?.collectorId === col.id).reduce((s,p)=>s+p.amount,0);
  const overdue = invoices.filter(inv => daysLate(inv) > 0).reduce((s,inv)=>s+invoiceBalance(inv),0);
  return { ...col, collected, overdue };
});

const AR_TREND = [
  { date:'2026-04-15', due:94_000_000, collected:18_500_000 },
  { date:'2026-04-16', due:101_000_000, collected:22_200_000 },
  { date:'2026-04-17', due:116_000_000, collected:14_600_000 },
  { date:'2026-04-18', due:124_000_000, collected:20_000_000 },
  { date:'2026-04-19', due:137_000_000, collected:8_000_000 },
  { date:'2026-04-20', due:148_000_000, collected:16_750_000 },
  { date:'2026-04-21', due:159_000_000, collected:11_250_000 },
  { date:'2026-04-22', due:172_000_000, collected:17_500_000 },
];

const KPI = (() => {
  const totalAR = INVOICES.reduce((s,inv)=>s+invoiceBalance(inv),0);
  const overdue = INVOICES.filter(inv => daysLate(inv) > 0).reduce((s,inv)=>s+invoiceBalance(inv),0);
  const current = totalAR - overdue;
  const collectedMTD = PAYMENTS.reduce((s,p)=>s+p.amount,0);
  const disputed = INVOICES.filter(inv => inv.dispute).reduce((s,inv)=>s+invoiceBalance(inv),0);
  return {
    totalAR,
    overdue,
    current,
    collectedMTD,
    disputed,
    dso: 34,
    overdueRatio: Math.round(overdue / totalAR * 100),
    promiseToday: FOLLOWUPS.filter(f => f.promiseDate === TODAY).length,
    tasksToday: TASKS.filter(t => t.dueToday).length,
  };
})();

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(1).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(' ').slice(0,2).map(w=>w[0]).join('').toUpperCase(); }
function collectorById(id) { return COLLECTORS.find(c => c.id === id); }
function invoiceById(id) { return INVOICES.find(i => i.id === id); }
function bucketLabel(b) { return b === 'current' ? 'Belum Jatuh Tempo' : b === 'd1' ? '1-7 Hari' : b === 'd8' ? '8-30 Hari' : b === 'd31' ? '31-60 Hari' : '60+ Hari'; }
function statusLabel(s) { return s === 'open' ? 'Open' : s === 'due' ? 'Jatuh Tempo' : s === 'overdue' ? 'Overdue' : s === 'partial' ? 'Sebagian' : s === 'matched' ? 'Matched' : s === 'pending' ? 'Pending' : s === 'unmatched' ? 'Unmatched' : s; }

Object.assign(window, {
  TENANT, TODAY, PERIODE, PERIODE_LABEL, ROLES, COLLECTORS, CUSTOMERS, CUSTOMER_BY_ID,
  INVOICES, FOLLOWUPS, PAYMENTS, TASKS, COLLECTION_TARGET, AR_TREND, KPI,
  rupiah, formatDateID, initials, collectorById, invoiceById, daysLate, invoiceBalance, agingBucket, bucketLabel, statusLabel,
});
