import { afterEach, beforeEach, expect, test } from 'bun:test';
import { fixture } from './test-fixture';
let f: ReturnType<typeof fixture>;
beforeEach(() => { f = fixture(); }); afterEach(() => f.close());
const create = (extra = {}) => f.json('/habits', 'POST', { name: 'Practice', method: 'count', target: 8, ...extra }, 201);
const day = (id: string, date: string) => f.json(`/habits/${id}/days/${date}`);
const log = (id: string, date: string, count: number) => f.json(`/habits/${id}/days/${date}/progress`, 'PUT', { count });
test('all default habits reset daily including partial counts and completed tasks', async () => {
  const h = await create(); expect(h.carryPartialProgress).toBe(false); await log(h.id, '2026-09-04', 7);
  const m = await f.json('/habits', 'POST', { name: 'Manual', method: 'manual' }, 201);
  await f.json(`/habits/${m.id}/days/2026-09-04/progress`, 'PUT', { done: true });
  const t = await f.json('/habits', 'POST', { name: 'Task', method: 'tasks', tasks: [{ name: 'One' }, { name: 'Two' }] }, 201);
  await f.json(`/habits/${t.id}/days/2026-09-04/tasks/${t.tasks[0].id}`, 'PUT', { done: true });
  f.setTime('2026-09-05T12:00Z');
  for (const id of [h.id, m.id, t.id]) expect((await day(id, '2026-09-05')).value).toBe(0);
});
test('opt-in partial counts carry to the next due date and completed counts reset', async () => {
  const h = await create({ carryPartialProgress: true, schedule: { type: 'interval', every: 3, anchor: '2026-09-04' } });
  await log(h.id, '2026-09-04', 7); f.setTime('2026-09-07T12:00Z');
  expect(await day(h.id, '2026-09-05')).toMatchObject({ due: false, value: 0 });
  expect(await day(h.id, '2026-09-07')).toMatchObject({ value: 7, carriedFrom: '2026-09-04', loggedCount: null });
  await log(h.id, '2026-09-07', 8); f.setTime('2026-09-10T12:00Z');
  expect((await day(h.id, '2026-09-10')).value).toBe(0);
});
test('backfills recompute inherited values but never overwrite explicit daily logs', async () => {
  const h = await create({ carryPartialProgress: true }); await log(h.id, '2026-09-04', 4);
  f.setTime('2026-09-07T12:00Z'); expect((await day(h.id, '2026-09-07')).value).toBe(4);
  await log(h.id, '2026-09-04', 7); expect((await day(h.id, '2026-09-06')).value).toBe(7);
  await log(h.id, '2026-09-06', 2); await log(h.id, '2026-09-04', 1);
  expect((await day(h.id, '2026-09-05')).value).toBe(1); expect((await day(h.id, '2026-09-07')).value).toBe(2);
  await log(h.id, '2026-09-06', 0); expect((await day(h.id, '2026-09-07')).value).toBe(0);
});
test('carryover configuration is dated and method switches break inheritance', async () => {
  const h = await create({ carryPartialProgress: true }); await log(h.id, '2026-09-04', 7);
  f.setTime('2026-09-05T12:00Z'); expect((await day(h.id, '2026-09-05')).value).toBe(7);
  await f.json(`/habits/${h.id}`, 'PATCH', { carryPartialProgress: false });
  expect((await day(h.id, '2026-09-05')).value).toBe(0); expect((await day(h.id, '2026-09-04')).value).toBe(7);
  await f.json(`/habits/${h.id}`, 'PATCH', { method: 'manual' });
  f.setTime('2026-09-06T12:00Z'); await f.json(`/habits/${h.id}`, 'PATCH', { method: 'count', target: 8, carryPartialProgress: true });
  expect((await day(h.id, '2026-09-06')).value).toBe(0);
  expect((await f.request('/habits', 'POST', { name: 'No partial state', method: 'manual', carryPartialProgress: true })).status).toBe(422);
});
