import { r as __exportAll } from "./chunk-olfrzTEO.js";
import { t as gql } from "./lib-Cfs4Tyom.js";
import { BaseSubgraph } from "@powerhousedao/reactor-api";
//#region subgraphs/budget-statements/schema.ts
const schema = gql`
  """
  Subgraph definition
  """
  type Query {
    budgetStatements(filter: budgetStatementsFilter): [BudgetStatement!]!
  }

  input budgetStatementsFilter {
    teamId: PHID
    networkSlug: String
  }

  type BudgetStatement {
    id: OID!
    owner: BudgetStatementOwner!
    operationalHubMember: OperationalHubMember
    month: String! ## JAN2026
    status: String!
    lastModifiedAtUtcIso: DateTime!
    reportedActuals: Amount_Currency!
    netExpenseTxns: Amount_Currency!
    snapshotReport: BudgetStatementSnapshotReport!
    expenseReport: BudgetStatementExpenseReport!
  }

  type OperationalHubMember {
    phid: PHID
    name: String
  }

  type BudgetStatementOwner {
    id: PHID!
    name: String!
    code: String!
    logo: URL!
  }

  type BudgetStatementSnapshotReport {
    startDate: DateTime!
    endDate: DateTime!
    accounts: [SnapshotAccount!]!
  }

  type SnapshotAccount {
    id: ID!
    name: String!
    address: String!
    type: SnapAccountType!
    balances: [SnapshotAccountBalance!]!
    transactions: [SnapshotAccountTransaction!]!
  }

  type SnapshotAccountBalance {
    startingBalance: Amount_Currency!
    endingBalance: Amount_Currency!
    token: Token!
  }

  type Token {
    symbol: String!
    contractAddress: EthereumAddress!
  }

  enum SnapAccountType {
    Source
    Internal
    Destination
    External
  }

  type SnapshotAccountTransaction {
    id: ID!
    datetime: DateTime!
    txHash: String!
    counterParty: EthereumAddress!
    counterPartyName: String!
    amount: TxAmount!
    direction: AccountTransactionDirection!
    flowType: AccountTransactionFlowType!
  }

  type TxAmount {
    value: Amount_Currency!
    unit: String!
  }

  enum AccountTransactionDirection {
    INFLOW
    OUTFLOW
  }

  enum AccountTransactionFlowType {
    TopUp
    Return
    Internal
    External
    Swap
  }

  type BudgetStatementExpenseReport {
    periodStart: DateTime!
    periodEnd: DateTime!
    groups: [ExpenseReportGroup!]!
    wallets: [ExpenseReportWallet!]!
  }

  type ExpenseReportGroup {
    id: ID!
    label: String!
    parentId: ID!
  }

  type ExpenseReportWallet {
    name: String
    address: EthereumAddress
    totals: [ExpenseReportGroupTotals!]!
    lineItems: [ExpenseReportLineItem!]!
    billingStatementIds: [PHID!]!
  }

  type ExpenseReportGroupTotals {
    group: ID!
    groupLabel: String!
    totalBudget: Amount_Currency!
    totalForecast: Amount_Currency!
    totalActuals: Amount_Currency!
    totalPayments: Amount_Currency!
  }

  type ExpenseReportLineItem {
    id: ID!
    label: String!
    groupId: ID!
    groupLabel: String! # resolved from groups
    budget: Amount_Currency!
    forecast: Amount_Currency!
    actuals: Amount_Currency!
    payments: Amount_Currency!
    comments: String
  }
`;
//#endregion
//#region subgraphs/budget-statements/resolvers.ts
const extractIsoDate = (dateStr) => {
	const match = dateStr.match(/^(\d{4}-\d{2}-\d{2})/);
	return match ? match[1] : null;
};
const getPeriodKey = (periodStart, periodEnd) => {
	if (!periodStart || !periodEnd) return null;
	const start = extractIsoDate(periodStart);
	const end = extractIsoDate(periodEnd);
	if (!start || !end) return null;
	return `${start}_${end}`;
};
const MONTHS = [
	"JAN",
	"FEB",
	"MAR",
	"APR",
	"MAY",
	"JUN",
	"JUL",
	"AUG",
	"SEP",
	"OCT",
	"NOV",
	"DEC"
];
const getMonthKey = (dateStr) => {
	if (!dateStr) return null;
	const match = dateStr.match(/^(\d{4})-(\d{2})/);
	if (!match) return null;
	const year = match[1];
	const monthIndex = parseInt(match[2], 10) - 1;
	if (monthIndex < 0 || monthIndex > 11) return null;
	return `${MONTHS[monthIndex]}${year}`;
};
const sortByMonth = (a, b) => {
	const parseMonth = (m) => {
		const months = {
			JAN: 0,
			FEB: 1,
			MAR: 2,
			APR: 3,
			MAY: 4,
			JUN: 5,
			JUL: 6,
			AUG: 7,
			SEP: 8,
			OCT: 9,
			NOV: 10,
			DEC: 11
		};
		const monthStr = m.substring(0, 3);
		const year = parseInt(m.substring(3), 10);
		return new Date(year, months[monthStr] || 0).getTime();
	};
	return parseMonth(b.month) - parseMonth(a.month);
};
const getResolvers = (subgraph) => {
	const { reactorClient } = subgraph;
	return { Query: { budgetStatements: async (_, args) => {
		const { teamId, networkSlug } = args.filter || {};
		const [snapshotResults, expenseResults, builderProfileResults] = await Promise.all([
			reactorClient.find({ type: "powerhouse/snapshot-report" }),
			reactorClient.find({ type: "powerhouse/expense-report" }),
			reactorClient.find({ type: "powerhouse/builder-profile" })
		]);
		let snapshotReportDocs = snapshotResults.results;
		let expenseReportDocs = expenseResults.results;
		const builderProfileDocs = /* @__PURE__ */ new Map();
		for (const doc of builderProfileResults.results) builderProfileDocs.set(doc.header.id, doc);
		let allowedBuilderPhids = null;
		if (networkSlug) {
			const targetNetworkSlug = networkSlug.toLowerCase().trim();
			if ((await reactorClient.find({ type: "powerhouse/network-profile" })).results.find((doc) => {
				const state = doc.state.global;
				if (!state?.name) return false;
				return state.name.toLowerCase().trim().split(/\s+/).join("-") === targetNetworkSlug;
			})) {
				const buildersDoc = (await reactorClient.find({ type: "powerhouse/builders" })).results[0];
				if (buildersDoc) {
					const state = buildersDoc.state.global;
					if (Array.isArray(state?.builders)) allowedBuilderPhids = new Set(state.builders.filter((id) => typeof id === "string"));
				}
			}
			if (!allowedBuilderPhids) return [];
		}
		if (allowedBuilderPhids) snapshotReportDocs = snapshotReportDocs.filter((doc) => {
			const ownerId = doc.state.global.ownerIds?.[0] ?? null;
			return !ownerId || allowedBuilderPhids.has(ownerId);
		});
		expenseReportDocs = expenseReportDocs.filter((doc) => {
			const ownerId = doc.state.global.ownerId;
			if (teamId && ownerId !== teamId) return false;
			if (allowedBuilderPhids && ownerId && !allowedBuilderPhids.has(ownerId)) return false;
			return true;
		});
		const resolvedProfiles = /* @__PURE__ */ new Map();
		const builderToOpHub = /* @__PURE__ */ new Map();
		const resolveProfile = async (phid) => {
			if (resolvedProfiles.has(phid)) return resolvedProfiles.get(phid);
			let doc = builderProfileDocs.get(phid) || null;
			if (!doc) try {
				doc = await reactorClient.get(phid);
			} catch {}
			const state = doc ? doc.state?.global ?? null : null;
			resolvedProfiles.set(phid, state);
			if (state?.operationalHubMember?.phid) builderToOpHub.set(phid, state.operationalHubMember.phid);
			return state;
		};
		const allOwnerIds = /* @__PURE__ */ new Set();
		for (const doc of snapshotReportDocs) {
			const id = doc.state.global.ownerIds?.[0];
			if (id) allOwnerIds.add(id);
		}
		for (const doc of expenseReportDocs) {
			const id = doc.state.global.ownerId;
			if (id) allOwnerIds.add(id);
		}
		await Promise.all(Array.from(allOwnerIds).map((id) => resolveProfile(id)));
		const budgetStatementsByOwnerAndPeriod = /* @__PURE__ */ new Map();
		const snapshotByOpHub = /* @__PURE__ */ new Map();
		for (const snapshotDoc of snapshotReportDocs) {
			const state = snapshotDoc.state.global;
			const ownerId = state.ownerIds?.[0] ?? null;
			if (!ownerId) continue;
			const periodKey = getPeriodKey(state.reportPeriodStart, state.reportPeriodEnd);
			if (!periodKey) continue;
			const key = `${ownerId}_${periodKey}`;
			if (!budgetStatementsByOwnerAndPeriod.has(key)) budgetStatementsByOwnerAndPeriod.set(key, {
				ownerId,
				periodKey,
				snapshotReport: null,
				expenseReport: null
			});
			budgetStatementsByOwnerAndPeriod.get(key).snapshotReport = snapshotDoc;
			const opHubPhid = builderToOpHub.get(ownerId);
			if (opHubPhid) snapshotByOpHub.set(`${opHubPhid}_${periodKey}`, snapshotDoc);
		}
		for (const expenseDoc of expenseReportDocs) {
			const state = expenseDoc.state.global;
			const ownerId = state.ownerId;
			if (!ownerId) continue;
			const periodKey = getPeriodKey(state.periodStart, state.periodEnd);
			if (!periodKey) continue;
			const key = `${ownerId}_${periodKey}`;
			if (!budgetStatementsByOwnerAndPeriod.has(key)) budgetStatementsByOwnerAndPeriod.set(key, {
				ownerId,
				periodKey,
				snapshotReport: null,
				expenseReport: null
			});
			budgetStatementsByOwnerAndPeriod.get(key).expenseReport = expenseDoc;
		}
		for (const entry of budgetStatementsByOwnerAndPeriod.values()) {
			if (entry.snapshotReport) continue;
			const opHubPhid = builderToOpHub.get(entry.ownerId);
			if (!opHubPhid) continue;
			const opHubSnapshot = snapshotByOpHub.get(`${opHubPhid}_${entry.periodKey}`);
			if (opHubSnapshot) entry.snapshotReport = opHubSnapshot;
		}
		const budgetStatements = [];
		for (const [key, { ownerId, periodKey, snapshotReport, expenseReport }] of budgetStatementsByOwnerAndPeriod.entries()) {
			const ownerState = resolvedProfiles.get(ownerId) ?? null;
			const owner = {
				id: ownerId,
				name: ownerState?.name || "Unknown",
				code: ownerState?.code || "",
				logo: ownerState?.icon || ""
			};
			const month = getMonthKey(snapshotReport?.state.global.reportPeriodStart || expenseReport?.state.global.periodStart || null) || periodKey;
			const snapshotReportData = snapshotReport ? buildSnapshotReportData(snapshotReport) : {
				startDate: "",
				endDate: "",
				accounts: []
			};
			const expenseReportData = expenseReport ? buildExpenseReportData(expenseReport) : {
				periodStart: "",
				periodEnd: "",
				groups: [],
				wallets: []
			};
			const status = expenseReport?.state.global.status || "DRAFT";
			const lastModifiedAtUtcIso = expenseReport?.header.lastModifiedAtUtcIso || "";
			const opHubMember = ownerState?.operationalHubMember ?? null;
			const operationalHubMember = opHubMember?.phid || opHubMember?.name ? {
				phid: opHubMember.phid || null,
				name: opHubMember.name || null
			} : null;
			budgetStatements.push({
				id: key,
				owner,
				operationalHubMember,
				month,
				status,
				lastModifiedAtUtcIso,
				reportedActuals: computeReportedActuals(expenseReportData),
				netExpenseTxns: computeNetExpenseTxns(snapshotReportData),
				snapshotReport: snapshotReportData,
				expenseReport: expenseReportData
			});
		}
		const opHubActuals = /* @__PURE__ */ new Map();
		for (const stmt of budgetStatements) {
			const opHubPhid = stmt.operationalHubMember?.phid;
			if (!opHubPhid) continue;
			const groupKey = `${opHubPhid}_${stmt.month}`;
			const current = opHubActuals.get(groupKey) || 0;
			opHubActuals.set(groupKey, current + (parseFloat(stmt.reportedActuals.value) || 0));
		}
		for (const stmt of budgetStatements) {
			const opHubPhid = stmt.operationalHubMember?.phid;
			if (!opHubPhid) continue;
			const groupKey = `${opHubPhid}_${stmt.month}`;
			const total = opHubActuals.get(groupKey);
			if (total !== void 0) stmt.reportedActuals = {
				unit: "USDS",
				value: String(total)
			};
		}
		const filteredStatements = teamId ? budgetStatements.filter((stmt) => stmt.owner.id === teamId) : budgetStatements;
		filteredStatements.sort(sortByMonth);
		return filteredStatements;
	} } };
};
/**
* Build snapshot report data from a SnapshotReportDocument
*/
function buildSnapshotReportData(doc) {
	const state = doc.state.global;
	return {
		startDate: state.reportPeriodStart || state.startDate || "",
		endDate: state.reportPeriodEnd || state.endDate || "",
		accounts: state.snapshotAccounts.map((account) => {
			const balances = account.startingBalances.map((startBal, index) => {
				const endBal = account.endingBalances[index] || {
					amount: {
						unit: startBal.token,
						value: "0"
					},
					token: startBal.token
				};
				return {
					startingBalance: startBal.amount,
					endingBalance: endBal.amount,
					token: {
						symbol: startBal.token,
						contractAddress: ""
					}
				};
			});
			const transactions = account.transactions.map((tx) => ({
				id: tx.id,
				datetime: tx.datetime,
				txHash: tx.txHash,
				counterParty: tx.counterParty || "",
				counterPartyName: getCounterPartyName(tx.counterParty, state.snapshotAccounts),
				amount: {
					value: tx.amount,
					unit: tx.token
				},
				direction: tx.direction,
				flowType: tx.flowType || "External"
			}));
			return {
				id: account.id,
				name: account.accountName,
				address: account.accountAddress,
				type: account.type,
				balances,
				transactions
			};
		})
	};
}
/**
* Build expense report data from an ExpenseReportDocument
*/
function buildExpenseReportData(doc) {
	const state = doc.state.global;
	const groups = state.groups.map((group) => ({
		id: group.id,
		label: group.label || "",
		parentId: group.parentId || ""
	}));
	const groupLabelMap = /* @__PURE__ */ new Map();
	for (const group of state.groups) groupLabelMap.set(group.id, group.label || "");
	const wallets = state.wallets.map((wallet) => {
		const totals = (wallet.totals || []).filter((t) => t !== null).map((total) => ({
			group: total.group || "",
			groupLabel: groupLabelMap.get(total.group || "") || "",
			totalBudget: {
				unit: "USDS",
				value: String(total.totalBudget || 0)
			},
			totalForecast: {
				unit: "USDS",
				value: String(total.totalForecast || 0)
			},
			totalActuals: {
				unit: "USDS",
				value: String(total.totalActuals || 0)
			},
			totalPayments: {
				unit: "USDS",
				value: String(total.totalPayments || 0)
			}
		}));
		const lineItems = (wallet.lineItems || []).filter((li) => li !== null).map((item) => ({
			id: item.id || "",
			label: item.label || "",
			groupId: item.group || "",
			groupLabel: groupLabelMap.get(item.group || "") || "",
			budget: {
				unit: "USDS",
				value: String(item.budget || 0)
			},
			forecast: {
				unit: "USDS",
				value: String(item.forecast || 0)
			},
			actuals: {
				unit: "USDS",
				value: String(item.actuals || 0)
			},
			payments: {
				unit: "USDS",
				value: String(item.payments || 0)
			},
			comments: item.comments || null
		}));
		const billingStatementIds = (wallet.billingStatements || []).filter((id) => id !== null);
		return {
			name: wallet.name || null,
			address: wallet.wallet || null,
			totals,
			lineItems,
			billingStatementIds
		};
	});
	return {
		periodStart: state.periodStart || "",
		periodEnd: state.periodEnd || "",
		groups,
		wallets
	};
}
/**
* Get counter party name by matching the counter party address
* against snapshot account addresses.
*/
function getCounterPartyName(counterPartyAddress, snapshotAccounts) {
	if (!counterPartyAddress) return "";
	return snapshotAccounts.find((acc) => acc.accountAddress.toLowerCase() === counterPartyAddress.toLowerCase())?.accountName || "";
}
/**
* Sum of all line item actuals from expense report wallets
*/
function computeReportedActuals(expenseReportData) {
	let total = 0;
	for (const wallet of expenseReportData.wallets) for (const item of wallet.lineItems) total += parseFloat(item.actuals.value) || 0;
	return {
		unit: "USDS",
		value: String(total)
	};
}
const USD_STABLECOINS = new Set([
	"USDS",
	"USDC",
	"DAI"
]);
/**
* Sum of outbound USD stablecoin transactions that leave the Internal wallet grouping.
* Excludes Swap (token conversion) and Internal (inter-wallet transfers) flowTypes.
* Only counts USDS, USDC, and DAI — excludes sUSDS, EURe, SKY, MKR, etc.
*/
function computeNetExpenseTxns(snapshotReportData) {
	let total = 0;
	for (const account of snapshotReportData.accounts) {
		if (account.type !== "Internal") continue;
		for (const tx of account.transactions) {
			if (tx.direction !== "OUTFLOW") continue;
			if (tx.flowType === "Swap" || tx.flowType === "Internal") continue;
			if (!USD_STABLECOINS.has(tx.amount.unit)) continue;
			total += parseFloat(tx.amount.value.value) || 0;
		}
	}
	return {
		unit: "USDS",
		value: String(total)
	};
}
//#endregion
//#region subgraphs/budget-statements/index.ts
var budget_statements_exports = /* @__PURE__ */ __exportAll({ BudgetStatementsSubgraph: () => BudgetStatementsSubgraph });
var BudgetStatementsSubgraph = class extends BaseSubgraph {
	name = "budget-statements";
	typeDefs = schema;
	resolvers = getResolvers(this);
	additionalContextFields = {};
	async onSetup() {}
	async onDisconnect() {}
};
//#endregion
export { budget_statements_exports as n, BudgetStatementsSubgraph as t };

//# sourceMappingURL=budget-statements-D_U_Exww.js.map