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

type Row = Record<string, any>;

const SOURCE_TYPE_LABELS: Record<string, string> = {
  manual: 'Manual',
  file_import: 'File import',
  provider_sync: 'Provider sync',
};

function sourceTypeLabel(type: unknown): string {
  return SOURCE_TYPE_LABELS[type as string] || String(type || 'Unknown');
}

function sourceLabel(source: Row = {}): string {
  if (source.type === 'manual' || source.provider === 'manual')
    return source.name || 'Manual Entry';
  if (source.name && source.provider) return `${source.name} (${source.provider})`;
  return source.name || source.provider || sourceTypeLabel(source.type);
}

function decorateDataSource(row: Row | null): Row | null {
  if (!row) return null;
  const safe = { ...row };
  delete safe.encrypted_secret;
  return {
    ...safe,
    source_label: sourceLabel(row),
    source_type_label: sourceTypeLabel(row.type),
  };
}

function decorateTransaction(row: Row | null): Row | null {
  if (!row) return null;
  const source = row.data_source_id
    ? {
        id: row.data_source_id,
        user_id: row.user_id,
        type: row.data_source_type || row.source_type,
        provider: row.data_source_provider,
        name: row.data_source_name,
        status: row.data_source_status,
      }
    : null;

  return {
    ...row,
    source_label: source ? sourceLabel(source) : sourceTypeLabel(row.source_type),
    source_type_label: sourceTypeLabel(row.source_type),
    data_source: source ? decorateDataSource(source) : null,
  };
}

function ensureManualDataSource(db: Db, userId: number): Row {
  const existing = db
    .prepare(
      `
    SELECT *
    FROM data_sources
    WHERE user_id = ? AND type = 'manual' AND provider = 'manual'
    ORDER BY id ASC
    LIMIT 1
  `,
    )
    .get(userId);
  if (existing) {
    if (existing.name !== 'Manual Entry' || existing.status !== 'active') {
      db.prepare(
        `
        UPDATE data_sources
        SET name = 'Manual Entry', status = 'active', updated_at = datetime('now')
        WHERE id = ? AND user_id = ?
      `,
      ).run(existing.id, userId);
      return db
        .prepare('SELECT * FROM data_sources WHERE id = ? AND user_id = ?')
        .get(existing.id, userId);
    }
    return existing;
  }

  const result = db
    .prepare(
      `
    INSERT INTO data_sources (user_id, type, provider, name, status)
    VALUES (?, 'manual', 'manual', 'Manual Entry', 'active')
  `,
    )
    .run(userId);
  return db
    .prepare('SELECT * FROM data_sources WHERE id = ? AND user_id = ?')
    .get(result.lastInsertRowid, userId);
}

function getTransactionForUser(db: Db, userId: number, id: number): Row | undefined {
  return db
    .prepare(
      `
    SELECT
      t.id, t.user_id, t.data_source_id, t.account_id, t.provider_transaction_id,
      t.source_type, t.transaction_type, t.posted_date, t.transacted_at, t.amount,
      t.currency, t.description, t.payee, t.memo, t.category, t.matched_bill_id,
      t.match_status, t.ignored, t.pending, t.created_at, t.updated_at,
      ds.type AS data_source_type, ds.provider AS data_source_provider,
      ds.name AS data_source_name, ds.status AS data_source_status,
      fa.name AS account_name, fa.org_name AS account_org_name,
      fa.account_type AS account_type,
      b.name AS matched_bill_name
    FROM transactions t
    LEFT JOIN data_sources ds ON ds.id = t.data_source_id AND ds.user_id = t.user_id
    LEFT JOIN financial_accounts fa ON fa.id = t.account_id AND fa.user_id = t.user_id
    LEFT JOIN bills b ON b.id = t.matched_bill_id AND b.user_id = t.user_id AND b.deleted_at IS NULL
    WHERE t.id = ? AND t.user_id = ?
      AND (t.account_id IS NULL OR fa.id IS NULL OR fa.monitored = 1)
  `,
    )
    .get(id, userId);
}

module.exports = {
  SOURCE_TYPE_LABELS,
  decorateDataSource,
  decorateTransaction,
  ensureManualDataSource,
  getTransactionForUser,
  sourceLabel,
  sourceTypeLabel,
};
