import { expect, test } from 'bun:test';
import { Database } from 'bun:sqlite';
import { drizzle } from 'drizzle-orm/bun-sqlite';
import { migrate } from 'drizzle-orm/bun-sqlite/migrator';
import { mkdtempSync, mkdirSync, readFileSync, writeFileSync, copyFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

test('carryover migration preserves pre-existing counts and explicit zero corrections', () => {
  const directory = mkdtempSync(join(tmpdir(), 'minabot-upgrade-'));
  const sqlite = new Database(':memory:'); sqlite.exec('PRAGMA foreign_keys = ON'); const db = drizzle(sqlite);
  try {
    mkdirSync(join(directory, 'meta'));
    const journal = JSON.parse(readFileSync('drizzle/meta/_journal.json', 'utf8'));
    journal.entries = journal.entries.slice(0, 2);
    writeFileSync(join(directory, 'meta/_journal.json'), JSON.stringify(journal));
    for (const entry of journal.entries) copyFileSync(`drizzle/${entry.tag}.sql`, join(directory, `${entry.tag}.sql`));
    migrate(db, { migrationsFolder: directory });
    sqlite.exec("INSERT INTO users (id, discord_id, username, created_at, updated_at) VALUES ('u', 'u', 'u', 0, 0)");
    sqlite.exec("INSERT INTO habits (id, user_id, created_date, created_at) VALUES ('h', 'u', '2026-09-04', 0)");
    sqlite.query('INSERT INTO habit_revisions (habit_id, effective_date, config, created_at) VALUES (?, ?, ?, ?)').run('h', '2026-09-04', JSON.stringify({ name: 'Old count', method: 'count', target: 8, unit: 'steps', schedule: { type: 'daily' }, archived: false }), 0);
    for (const [date, count] of [['2026-09-04', 7], ['2026-09-05', 0], ['2026-09-06', 0]] as const) sqlite.query('INSERT INTO habit_days (habit_id, revision_id, date, timezone, ends_at, count) VALUES (?, ?, ?, ?, ?, ?)').run('h', 1, date, 'UTC', 0, count);
    sqlite.query('INSERT INTO progress_events (day_id, before, after, created_at) VALUES (?, ?, ?, ?)').run(2, '{"count":2}', '{"count":0}', 0);
    migrate(db, { migrationsFolder: './drizzle' }); migrate(db, { migrationsFolder: './drizzle' });
    expect(sqlite.query('SELECT count, count_set FROM habit_days ORDER BY id').all()).toEqual([{ count: 7, count_set: 1 }, { count: 0, count_set: 1 }, { count: 0, count_set: 0 }]);
    const config = (sqlite.query('SELECT config FROM habit_revisions').get() as { config: string }).config;
    expect(JSON.parse(config).carryPartialProgress).toBe(false);
  } finally { sqlite.close(); rmSync(directory, { recursive: true, force: true }); }
});

test('deadline migration repairs historical expiry using the original state before corrections', () => {
  const directory = mkdtempSync(join(tmpdir(), 'minabot-expiry-upgrade-'));
  const sqlite = new Database(':memory:'); const db = drizzle(sqlite);
  try {
    mkdirSync(join(directory, 'meta'));
    const journal = JSON.parse(readFileSync('drizzle/meta/_journal.json', 'utf8'));
    journal.entries = journal.entries.slice(0, 3);
    writeFileSync(join(directory, 'meta/_journal.json'), JSON.stringify(journal));
    for (const entry of journal.entries) copyFileSync(`drizzle/${entry.tag}.sql`, join(directory, `${entry.tag}.sql`));
    migrate(db, { migrationsFolder: directory });
    sqlite.exec("INSERT INTO users (id, discord_id, username, created_at, updated_at) VALUES ('u', 'u', 'u', 0, 0)");
    sqlite.exec("INSERT INTO habits (id, user_id, created_date, created_at) VALUES ('h', 'u', '2020-01-01', 0)");
    sqlite.query('INSERT INTO habit_revisions (habit_id, effective_date, config, created_at) VALUES (?, ?, ?, ?)').run('h', '2020-01-01', JSON.stringify({ name: 'Tasks', method: 'tasks', tasks: [], schedule: { type: 'daily' }, archived: false }), 0);
    sqlite.exec("INSERT INTO habit_days (habit_id, revision_id, date, timezone, ends_at) VALUES ('h', 1, '2020-01-01', 'UTC', 100)");
    sqlite.exec("INSERT INTO task_occurrences (id, day_id, task_id, name, done, expired_at, updated_at) VALUES ('a', 1, 'a', 'Originally completed', 0, 100, 200), ('b', 1, 'b', 'Originally incomplete', 1, 100, 200)");
    sqlite.query('INSERT INTO progress_events (day_id, occurrence_id, before, after, created_at) VALUES (?, ?, ?, ?, ?)').run(1, 'a', '{"done":true}', '{"done":false}', 200);
    sqlite.query('INSERT INTO progress_events (day_id, occurrence_id, before, after, created_at) VALUES (?, ?, ?, ?, ?)').run(1, 'b', '{"done":false}', '{"done":true}', 200);
    migrate(db, { migrationsFolder: './drizzle' });
    expect(sqlite.query('SELECT id, expired_at, closed_at, done FROM task_occurrences ORDER BY id').all()).toEqual([
      { id: 'a', expired_at: null, closed_at: 100, done: 0 }, { id: 'b', expired_at: 100, closed_at: 100, done: 1 },
    ]);
  } finally { sqlite.close(); rmSync(directory, { recursive: true, force: true }); }
});
