import "server-only";

import { Query } from "node-appwrite";

import {
  DATABASE_ID,
  TABLES,
  type FinanceEntry,
  type TenantKind,
  type TenantSettings,
} from "./schema";
import { createAdminClient } from "./server";
import { toPlain } from "./serialize";

export type FinanceCounterpart = {
  tenantId: string;
  companyName: string;
  kind: TenantKind;
};

export type FinanceEntryWithCounterpart = FinanceEntry & {
  counterpart: FinanceCounterpart | null;
};

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

  const counterpartIds = Array.from(
    new Set(rows.map((r) => r.counterpartTenantId).filter((v): v is string => Boolean(v))),
  );
  if (counterpartIds.length === 0) {
    return toPlain(rows.map((r) => ({ ...r, counterpart: null })));
  }

  const counterpartsRes = await tablesDB.listRows({
    databaseId: DATABASE_ID,
    tableId: TABLES.tenantSettings,
    queries: [Query.equal("tenantId", counterpartIds), Query.limit(200)],
  });
  const map = new Map<string, FinanceCounterpart>();
  for (const s of counterpartsRes.rows as unknown as TenantSettings[]) {
    map.set(s.tenantId, {
      tenantId: s.tenantId,
      companyName: s.companyName,
      kind: s.kind,
    });
  }

  return toPlain(
    rows.map((r) => ({
      ...r,
      counterpart: r.counterpartTenantId ? map.get(r.counterpartTenantId) ?? null : null,
    })),
  );
}

export function summarizeFinance(
  entries: FinanceEntryWithCounterpart[],
): {
  receivablePending: number;
  payablePending: number;
  incomeThisMonth: number;
  expenseThisMonth: number;
  currency: string;
} {
  const now = new Date();
  const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
  let receivablePending = 0;
  let payablePending = 0;
  let incomeThisMonth = 0;
  let expenseThisMonth = 0;
  const currency = entries.find((e) => e.currency)?.currency || "TRY";

  for (const e of entries) {
    if (e.status === "cancelled") continue;
    if (e.type === "receivable" && e.status === "pending") receivablePending += e.amount;
    if (e.type === "payable" && e.status === "pending") payablePending += e.amount;
    if (e.date >= monthStart) {
      if ((e.type === "income" || e.type === "receivable") && e.status === "paid") {
        incomeThisMonth += e.amount;
      }
      if ((e.type === "expense" || e.type === "payable") && e.status === "paid") {
        expenseThisMonth += e.amount;
      }
    }
  }

  return { receivablePending, payablePending, incomeThisMonth, expenseThisMonth, currency };
}
