'use strict';

import type { Db } from '../types/db';

const { ensureUserDefaultCategories } = require('../db/database.cts');

// Independent user-owned tables (each has a user_id) wiped wholesale.
const USER_TABLES = [
  'bill_merchant_rules',
  'match_suggestion_rejections',
  'autopay_suggestion_dismissals',
  'declined_subscription_hints',
  'subscription_recommendation_feedback',
  'user_catalog_descriptors',
  'spending_category_rules',
  'spending_budgets',
  'bill_templates',
  'snowball_plans',
  'monthly_starting_amounts',
  'monthly_income',
  'calendar_tokens',
  'import_sessions',
  'import_history',
];

/**
 * Permanently erase a user's financial + imported data, resetting them to a clean
 * slate — WITHOUT touching the account, sessions, 2FA/WebAuthn, login history, or
 * preferences. Runs in one transaction (child → parent order so it holds with
 * foreign_keys ON), then re-seeds default categories so the app stays usable and
 * writes an audit row to import_history.
 */
function eraseUserData(db: Db, userId: number): { erased: number; counts: Record<string, number> } {
  const counts: Record<string, number> = {};
  const del = (label: string, sql: string) => {
    counts[label] = db.prepare(sql).run(userId).changes;
  };

  const run = db.transaction(() => {
    // Bill-children (no user_id of their own) — remove before bills.
    del(
      'payments',
      'DELETE FROM payments WHERE bill_id IN (SELECT id FROM bills WHERE user_id = ?)',
    );
    del(
      'monthly_bill_state',
      'DELETE FROM monthly_bill_state WHERE bill_id IN (SELECT id FROM bills WHERE user_id = ?)',
    );
    del(
      'bill_history_ranges',
      'DELETE FROM bill_history_ranges WHERE bill_id IN (SELECT id FROM bills WHERE user_id = ?)',
    );

    // Bank-data chain: transactions → accounts → sources.
    del('transactions', 'DELETE FROM transactions WHERE user_id = ?');
    del('financial_accounts', 'DELETE FROM financial_accounts WHERE user_id = ?');
    del('data_sources', 'DELETE FROM data_sources WHERE user_id = ?');

    for (const t of USER_TABLES) del(t, `DELETE FROM ${t} WHERE user_id = ?`);

    // bills → categories → category_groups (bills.category_id, categories.group_id FKs).
    del('bills', 'DELETE FROM bills WHERE user_id = ?');
    del('categories', 'DELETE FROM categories WHERE user_id = ?');
    del('category_groups', 'DELETE FROM category_groups WHERE user_id = ?');
  });
  run();

  // Re-seed default categories so the app is immediately usable again.
  ensureUserDefaultCategories(userId);

  const erased = Object.values(counts).reduce((sum, n) => sum + n, 0);
  db.prepare(
    `
    INSERT INTO import_history (user_id, imported_at, source_filename, file_type,
      rows_parsed, rows_created, rows_updated, rows_skipped, rows_ambiguous, rows_errored, options_json, summary_json)
    VALUES (?, ?, 'erase-my-data', 'erase-data', ?, 0, 0, 0, 0, 0, ?, ?)
  `,
  ).run(
    userId,
    new Date().toISOString(),
    erased,
    JSON.stringify({ action: 'erase-my-data' }),
    JSON.stringify(counts),
  );

  return { erased, counts };
}

// User-scoped tables the demo seeder marks with is_seeded = 1 (not bill-children,
// which cascade with their seeded bill). Keep in sync with scripts/seedDemoData.cts
// and the v1.07 migration.
const DEMO_MARKER_TABLES = [
  'transactions',
  'financial_accounts',
  'data_sources',
  'category_groups',
  'bill_templates',
  'snowball_plans',
  'spending_category_rules',
  'spending_budgets',
  'monthly_income',
  'monthly_starting_amounts',
  'calendar_tokens',
  'declined_subscription_hints',
];

/**
 * Surgically remove ONLY the demo data seeded by scripts/seedDemoData.cts for one
 * user — never their real data. Runs in one transaction, child → parent so it holds
 * with foreign_keys ON. Marker tables go by is_seeded; bill-children cascade with the
 * seeded bill. A seeded category is removed only if no surviving (non-seeded) bill
 * still references it, so a user's own bill that reused a demo category keeps it.
 * Mirrors eraseUserData(); audits to import_history.
 */
function clearSeededDemoData(
  db: Db,
  userId: number,
): { removed: number; counts: Record<string, number> } {
  const counts: Record<string, number> = {};
  const del = (label: string, sql: string) => {
    counts[label] = db.prepare(sql).run(userId).changes;
  };

  const run = db.transaction(() => {
    // Bank chain first (transactions cascade their match rejections), then the rest
    // of the independent marker tables.
    for (const t of DEMO_MARKER_TABLES)
      del(t, `DELETE FROM ${t} WHERE user_id = ? AND is_seeded = 1`);

    // Bill-children counted explicitly (they also cascade with the bill below).
    del(
      'payments',
      'DELETE FROM payments WHERE bill_id IN (SELECT id FROM bills WHERE user_id = ? AND is_seeded = 1)',
    );
    del('bills', 'DELETE FROM bills WHERE user_id = ? AND is_seeded = 1');
    // Seeded categories only if no surviving bill still references them.
    counts.categories = db
      .prepare(
        `DELETE FROM categories WHERE user_id = ? AND is_seeded = 1
         AND id NOT IN (SELECT category_id FROM bills WHERE user_id = ? AND category_id IS NOT NULL)`,
      )
      .run(userId, userId).changes;
    // Reset the demo snowball extra-payment.
    db.prepare('UPDATE users SET snowball_extra_payment = 0 WHERE id = ?').run(userId);
  });
  run();

  const removed = Object.values(counts).reduce((sum, n) => sum + n, 0);
  db.prepare(
    `
    INSERT INTO import_history (user_id, imported_at, source_filename, file_type,
      rows_parsed, rows_created, rows_updated, rows_skipped, rows_ambiguous, rows_errored, options_json, summary_json)
    VALUES (?, ?, 'clear-demo-data', 'clear-demo', ?, 0, 0, 0, 0, 0, ?, ?)
  `,
  ).run(
    userId,
    new Date().toISOString(),
    removed,
    JSON.stringify({ action: 'clear-demo-data' }),
    JSON.stringify(counts),
  );

  return { removed, counts };
}

module.exports = { eraseUserData, clearSeededDemoData };
