'use strict';

// P1 — computeAmountSuggestionsBatch replaces up to 12 per-bill queries with two
// batched queries in getTracker. This pins that the batched form is byte-identical
// to calling the single-bill computeAmountSuggestion per bill (the behavior we
// rely on for the N+1 fix to be safe).
const test = require('node:test');
const assert = require('node:assert/strict');
const os = require('node:os');
const path = require('node:path');
const fs = require('node:fs');

const dbPath = path.join(os.tmpdir(), `bill-tracker-amountsug-${process.pid}.sqlite`);
process.env.DB_PATH = dbPath;

const { getDb, closeDb } = require('../db/database');
const { computeAmountSuggestion, computeAmountSuggestionsBatch } = require('../services/amountSuggestionService');

let db, userId, bills;
test.before(() => {
  db = getDb();
  userId = db.prepare("INSERT INTO users (username, password_hash, role, active) VALUES ('as-user','x','user',1)").run().lastInsertRowid;
  const insBill = db.prepare("INSERT INTO bills (user_id, name, due_day, expected_amount, active) VALUES (?, ?, 1, 10000, 1)");
  bills = {
    payments: insBill.run(userId, 'Payments only').lastInsertRowid,   // suggestion from payment sums
    mbs:      insBill.run(userId, 'Corrected').lastInsertRowid,        // user-corrected actual_amount wins
    mixed:    insBill.run(userId, 'Mixed').lastInsertRowid,           // some months mbs, some payments
    empty:    insBill.run(userId, 'No history').lastInsertRowid,      // → null suggestion
  };

  const pay = db.prepare("INSERT INTO payments (bill_id, amount, paid_date, payment_source) VALUES (?, ?, ?, 'manual')");
  // For query month = 2026-06: prior months are May, Apr, Mar, Feb, Jan 2026, Dec 2025.
  pay.run(bills.payments, 10000, '2026-05-15');
  pay.run(bills.payments, 12000, '2026-04-15');
  pay.run(bills.payments, 11000, '2026-03-15');
  // Two payments in one month should sum.
  pay.run(bills.mixed, 3000, '2026-05-10');
  pay.run(bills.mixed, 2000, '2026-05-20'); // May total 5000
  pay.run(bills.mixed, 9000, '2026-04-10');

  const mbs = db.prepare("INSERT INTO monthly_bill_state (bill_id, year, month, actual_amount) VALUES (?, ?, ?, ?)");
  mbs.run(bills.mbs, 2026, 5, 8000);
  mbs.run(bills.mbs, 2026, 4, 8500);
  mbs.run(bills.mbs, 2026, 3, 7500);
  // Mixed: March has a corrected amount that should win over any payment sum.
  mbs.run(bills.mixed, 2026, 3, 4200);
});
test.after(() => {
  closeDb();
  for (const s of ['', '-wal', '-shm']) { try { fs.rmSync(dbPath + s); } catch {} }
});

test('batch output equals per-bill computeAmountSuggestion for every bill', () => {
  const ids = Object.values(bills);
  const batch = computeAmountSuggestionsBatch(db, ids, 2026, 6);
  for (const id of ids) {
    const single = computeAmountSuggestion(db, id, 2026, 6);
    assert.deepEqual(batch.get(id), single, `bill ${id} batch matches single`);
  }
});

test('empty bill list returns an empty map; no-history bill → null', () => {
  assert.equal(computeAmountSuggestionsBatch(db, [], 2026, 6).size, 0);
  const batch = computeAmountSuggestionsBatch(db, [bills.empty], 2026, 6);
  assert.equal(batch.get(bills.empty), null);
});

test('corrected monthly amount wins over payment sums (median of mbs values)', () => {
  const s = computeAmountSuggestion(db, bills.mbs, 2026, 6);
  // median of [8000, 8500, 7500] = 8000 → $80
  assert.equal(s.suggestion, 80);
  assert.equal(s.months_used, 3);
  assert.equal(s.confidence, 'high');
});
