import { nowIso, uuid } from './utils.js';
import { withTransaction } from './db.js';

const ASSET_SUFFIX = Object.freeze({
  OC_POINTS: 'points',
  OC_TOKEN: 'token',
  USDT: 'usdt'
});

export function userAccountId(userId, asset) {
  const suffix = ASSET_SUFFIX[asset];
  if (!suffix) throw Object.assign(new Error(`Unsupported asset: ${asset}`), { code: 'UNSUPPORTED_ASSET', status: 400 });
  return `user:${userId}:${suffix}`;
}

export function ensureUserAccounts(db, userId) {
  const insert = db.prepare(`
    INSERT OR IGNORE INTO ledger_accounts(id,user_id,asset,code,name,allow_negative,balance,created_at)
    VALUES(?,?,?,?,?,0,0,?)
  `);
  insert.run(userAccountId(userId, 'OC_POINTS'), userId, 'OC_POINTS', `user:${userId}:points`, 'Kullanıcı OC_POINTS', nowIso());
  insert.run(userAccountId(userId, 'OC_TOKEN'), userId, 'OC_TOKEN', `user:${userId}:token`, 'Kullanıcı OC_TOKEN', nowIso());
  insert.run(userAccountId(userId, 'USDT'), userId, 'USDT', `user:${userId}:usdt`, 'Kullanıcı USDT', nowIso());
}

export function postTransferInTx(db, {
  fromAccountId,
  toAccountId,
  amount,
  type,
  ref,
  idempotencyKey,
  metadata = {}
}) {
  if (!Number.isSafeInteger(amount) || amount <= 0) {
    throw Object.assign(new Error('Amount must be a positive safe integer.'), { code: 'INVALID_AMOUNT', status: 400 });
  }
  const existing = db.prepare('SELECT id FROM ledger_transactions WHERE idempotency_key=?').get(idempotencyKey);
  if (existing) return { id: existing.id, duplicate: true };

  const from = db.prepare('SELECT * FROM ledger_accounts WHERE id=?').get(fromAccountId);
  const to = db.prepare('SELECT * FROM ledger_accounts WHERE id=?').get(toAccountId);
  if (!from || !to) throw Object.assign(new Error('Ledger account not found.'), { code: 'ACCOUNT_NOT_FOUND', status: 500 });
  if (from.asset !== to.asset) throw Object.assign(new Error('Asset mismatch.'), { code: 'ASSET_MISMATCH', status: 500 });
  if (!from.allow_negative && from.balance < amount) {
    throw Object.assign(new Error('Insufficient balance.'), { code: 'INSUFFICIENT_BALANCE', status: 409 });
  }

  const txId = uuid();
  const createdAt = nowIso();
  db.prepare(`INSERT INTO ledger_transactions(id,type,ref,idempotency_key,metadata,created_at) VALUES(?,?,?,?,?,?)`)
    .run(txId, type, ref, idempotencyKey, JSON.stringify(metadata), createdAt);
  db.prepare(`INSERT INTO ledger_entries(id,transaction_id,account_id,amount,created_at) VALUES(?,?,?,?,?)`)
    .run(uuid(), txId, from.id, -amount, createdAt);
  db.prepare(`INSERT INTO ledger_entries(id,transaction_id,account_id,amount,created_at) VALUES(?,?,?,?,?)`)
    .run(uuid(), txId, to.id, amount, createdAt);
  db.prepare('UPDATE ledger_accounts SET balance=balance-? WHERE id=?').run(amount, from.id);
  db.prepare('UPDATE ledger_accounts SET balance=balance+? WHERE id=?').run(amount, to.id);

  return {
    id: txId,
    duplicate: false,
    asset: from.asset,
    amount,
    fromBalance: from.balance - amount,
    toBalance: to.balance + amount
  };
}

export function postTransfer(db, input) {
  return withTransaction(db, () => postTransferInTx(db, input));
}

export function getBalance(db, accountId) {
  return db.prepare('SELECT balance FROM ledger_accounts WHERE id=?').get(accountId)?.balance ?? 0;
}

export function getUserBalances(db, userId) {
  ensureUserAccounts(db, userId);
  const rows = db.prepare('SELECT asset,balance FROM ledger_accounts WHERE user_id=?').all(userId);
  const result = { OC_POINTS: 0, OC_TOKEN: 0, USDT: 0 };
  for (const row of rows) result[row.asset] = row.balance;
  return result;
}

export function getUserTransactions(db, userId, limit = 50) {
  ensureUserAccounts(db, userId);
  const safeLimit = Math.max(1, Math.min(200, Number(limit) || 50));
  return db.prepare(`
    SELECT t.id, t.type, t.ref, t.metadata, t.created_at, a.asset, e.amount
    FROM ledger_entries e
    JOIN ledger_transactions t ON t.id=e.transaction_id
    JOIN ledger_accounts a ON a.id=e.account_id
    WHERE a.user_id=?
    ORDER BY t.created_at DESC
    LIMIT ?
  `).all(userId, safeLimit).map((row) => ({
    ...row,
    metadata: (() => { try { return JSON.parse(row.metadata); } catch { return {}; } })()
  }));
}

export function reconcileLedger(db) {
  const accountIssues = db.prepare(`
    SELECT a.id, a.code, a.balance, COALESCE(SUM(e.amount),0) AS computed
    FROM ledger_accounts a
    LEFT JOIN ledger_entries e ON e.account_id=a.id
    GROUP BY a.id
    HAVING a.balance <> computed
  `).all();
  const transactionIssues = db.prepare(`
    SELECT t.id, t.type, SUM(e.amount) AS total
    FROM ledger_transactions t
    JOIN ledger_entries e ON e.transaction_id=t.id
    GROUP BY t.id
    HAVING total <> 0
  `).all();
  return {
    ok: accountIssues.length === 0 && transactionIssues.length === 0,
    accountIssues,
    transactionIssues
  };
}
