import "server-only";

import { Query } from "node-appwrite";

import { canAccessRow } from "./scope-permissions";
import { createAdminClient } from "./server";
import {
  DATABASE_ID,
  TABLES,
  type BankAccount,
  type FinanceEntry,
} from "./schema";

/**
 * Returns bank accounts the current user is allowed to see:
 * - all `company` scope rows
 * - personal-scope rows where createdBy === currentUserId
 */
export async function listBankAccounts(
  tenantId: string,
  currentUserId?: string,
): Promise<BankAccount[]> {
  try {
    const { tablesDB } = createAdminClient();
    const result = await tablesDB.listRows({
      databaseId: DATABASE_ID,
      tableId: TABLES.bankAccounts,
      queries: [
        Query.equal("tenantId", tenantId),
        Query.orderAsc("bankName"),
        Query.limit(200),
      ],
    });
    const rows = result.rows as unknown as BankAccount[];
    if (!currentUserId) return rows;
    return rows.filter((r) => canAccessRow(r, currentUserId));
  } catch {
    return [];
  }
}

/**
 * Computes a current balance for each visible account.
 */
export async function getBankAccountBalances(
  tenantId: string,
  currentUserId?: string,
): Promise<Map<string, number>> {
  const balances = new Map<string, number>();
  try {
    const accounts = await listBankAccounts(tenantId, currentUserId);
    const visibleIds = new Set(accounts.map((a) => a.$id));
    for (const a of accounts) balances.set(a.$id, a.openingBalance ?? 0);

    const { tablesDB } = createAdminClient();
    const entries = await tablesDB.listRows({
      databaseId: DATABASE_ID,
      tableId: TABLES.financeEntries,
      queries: [
        Query.equal("tenantId", tenantId),
        Query.isNotNull("bankAccountId"),
        Query.limit(5000),
      ],
    });
    for (const e of entries.rows as unknown as FinanceEntry[]) {
      if (!e.bankAccountId || !visibleIds.has(e.bankAccountId)) continue;
      const cur = balances.get(e.bankAccountId);
      if (cur === undefined) continue;
      if (e.type === "income") balances.set(e.bankAccountId, cur + e.amount);
      else if (e.type === "expense") balances.set(e.bankAccountId, cur - e.amount);
    }
  } catch {
    /* ignore */
  }
  return balances;
}

export async function listEntriesForAccount(
  tenantId: string,
  bankAccountId: string,
  limit = 25,
): Promise<FinanceEntry[]> {
  try {
    const { tablesDB } = createAdminClient();
    const result = await tablesDB.listRows({
      databaseId: DATABASE_ID,
      tableId: TABLES.financeEntries,
      queries: [
        Query.equal("tenantId", tenantId),
        Query.equal("bankAccountId", bankAccountId),
        Query.orderDesc("date"),
        Query.limit(limit),
      ],
    });
    return result.rows as unknown as FinanceEntry[];
  } catch {
    return [];
  }
}
