/**
 * Flow types — framework-agnostic (ported from rflows-online, @xyflow removed).
 */

export interface IntegrationSource {
	type: "rvote" | "safe" | "manual";
	safeAddress?: string;
	safeChainId?: number;
	tokenAddress?: string | null;
	tokenSymbol?: string;
	tokenDecimals?: number;
	rvoteSpaceSlug?: string;
	rvoteProposalId?: string;
	rvoteProposalStatus?: string;
	rvoteProposalScore?: number;
	lastFetchedAt?: number;
}

export interface OverflowAllocation {
	targetId: string;
	percentage: number;
	color: string;
	waypoint?: { x: number; y: number };
}

export interface SpendingAllocation {
	targetId: string;
	percentage: number;
	color: string;
	waypoint?: { x: number; y: number };
}

export interface SourceAllocation {
	targetId: string;
	percentage: number;
	color: string;
	waypoint?: { x: number; y: number };
}

export type SufficiencyState = "seeking" | "approaching" | "overflowing";

export interface FunnelNodeData {
	label: string;
	currentValue: number;          // runtime accumulator, not user-editable
	overflowThreshold: number;     // triggers overflow routing
	capacity: number;              // visual max / clamp
	inflowRate: number;            // computed from upstream
	drainRate: number;             // flat drain $/mo
	overflowAllocations: OverflowAllocation[];
	spendingAllocations: SpendingAllocation[];
	source?: IntegrationSource;
	dripsConfig?: DripsNodeConfig;
	[key: string]: unknown;
}

/** Coerce a value to a finite number, defaulting to `fallback` for NaN/undefined/null/Infinity. */
function safeNum(v: unknown, fallback = 0): number {
	const n = Number(v);
	return Number.isFinite(n) ? n : fallback;
}

/** Migrate legacy FunnelNodeData (4-tier thresholds) to new 2-tier format. */
export function migrateFunnelNodeData(d: any): FunnelNodeData {
	return {
		label: d.label ?? "Funnel",
		currentValue: safeNum(d.currentValue),
		overflowThreshold: safeNum(d.overflowThreshold ?? d.maxThreshold),
		capacity: safeNum(d.capacity ?? d.maxCapacity),
		inflowRate: safeNum(d.inflowRate),
		drainRate: safeNum(d.drainRate ?? d.desiredOutflow ?? d.inflowRate),
		overflowAllocations: (d.overflowAllocations ?? []).map((a: any) => ({ ...a, percentage: safeNum(a.percentage) })),
		spendingAllocations: (d.spendingAllocations ?? []).map((a: any) => ({ ...a, percentage: safeNum(a.percentage) })),
		source: d.source,
	};
}

/** Sanitize OutcomeNodeData, ensuring all numeric fields are finite. */
export function migrateOutcomeNodeData(d: any): OutcomeNodeData {
	return {
		label: d.label ?? "Outcome",
		description: d.description ?? "",
		fundingReceived: safeNum(d.fundingReceived),
		fundingTarget: safeNum(d.fundingTarget),
		status: d.status || "not-started",
		phases: d.phases,
		overflowAllocations: d.overflowAllocations?.map((a: any) => ({ ...a, percentage: safeNum(a.percentage) })),
		source: d.source,
		linkedTaskIds: Array.isArray(d.linkedTaskIds) ? d.linkedTaskIds : [],
		linkedBoardId: d.linkedBoardId,
	};
}

/** Sanitize SourceNodeData, ensuring all numeric fields are finite. */
export function migrateSourceNodeData(d: any): SourceNodeData {
	return {
		label: d.label ?? "Source",
		flowRate: safeNum(d.flowRate),
		sourceType: d.sourceType || "unconfigured",
		targetAllocations: (d.targetAllocations ?? []).map((a: any) => ({
			targetId: a.targetId,
			percentage: safeNum(a.percentage),
			color: a.color ?? "#10b981",
		})),
		walletAddress: d.walletAddress,
		chainId: d.chainId,
		safeAddress: d.safeAddress,
		transakOrderId: d.transakOrderId,
		effectiveDate: d.effectiveDate,
	};
}

/** Sanitize any FlowNode's data based on its type. */
export function migrateNodeData(n: any): FlowNode {
	const type = n.type;
	let data;
	if (type === "funnel") data = migrateFunnelNodeData(n.data);
	else if (type === "outcome") data = migrateOutcomeNodeData(n.data);
	else if (type === "source") data = migrateSourceNodeData(n.data);
	else data = { ...n.data };
	return {
		id: n.id,
		type,
		position: { x: safeNum(n.position?.x), y: safeNum(n.position?.y) },
		data,
	};
}

export interface PhaseTask {
	label: string;
	completed: boolean;
}

export interface OutcomePhase {
	name: string;
	fundingThreshold: number;
	tasks: PhaseTask[];
}

export interface OutcomeNodeData {
	label: string;
	description?: string;
	fundingReceived: number;
	fundingTarget: number;
	status: "not-started" | "in-progress" | "completed" | "blocked";
	phases?: OutcomePhase[];
	overflowAllocations?: OverflowAllocation[];
	source?: IntegrationSource;
	dripsConfig?: DripsNodeConfig;
	/** Array of "{boardId}:{taskId}" strings linking to rTasks items */
	linkedTaskIds?: string[];
	/** Default rTasks board to link tasks from */
	linkedBoardId?: string;
	[key: string]: unknown;
}

export interface SourceNodeData {
	label: string;
	flowRate: number;
	sourceType: "card" | "safe_wallet" | "ridentity" | "metamask" | "unconfigured";
	targetAllocations: SourceAllocation[];
	walletAddress?: string;
	chainId?: number;
	safeAddress?: string;
	transakOrderId?: string;
	effectiveDate?: string;
	dripsConfig?: DripsNodeConfig;
	[key: string]: unknown;
}

/** Lightweight node (replaces @xyflow/react Node) */
export interface FlowNode {
	id: string;
	type: "funnel" | "outcome" | "source";
	position: { x: number; y: number };
	data: FunnelNodeData | OutcomeNodeData | SourceNodeData;
}

// ─── Drips integration ───────────────────────────────

export interface DripsNodeConfig {
	chainId: number;
	address: string;
	streamIds?: string[];
	splitWeight?: number;
	splitIndex?: number;
	isIntermediary?: boolean;
	importedAt: number;
}

// ─── Mortgage types ──────────────────────────────────

export interface MortgagePosition {
	id: string;
	borrower: string;
	borrowerDid: string;
	principal: number;
	interestRate: number;
	termMonths: number;
	monthlyPayment: number;
	startDate: number;
	trustScore: number;
	status: "active" | "paid-off" | "defaulted" | "pending";
	collateralType: "trust-backed" | "asset-backed" | "hybrid";
}

export interface ReinvestmentPosition {
	protocol: string;
	chain: string;
	asset: string;
	deposited: number;
	currentValue: number;
	apy: number;
	lastUpdated: number;
}

// ─── Budget types ─────────────────────────────────────

export interface BudgetSegment {
	id: string;
	name: string;
	color: string;
	createdBy: string | null;
}

export interface BudgetAllocation {
	participantDid: string;
	allocations: Record<string, number>; // segmentId → percentage (0-100)
	updatedAt: number;
}

// ─── Port definitions ─────────────────────────────────

export type PortDirection = "in" | "out";
export type PortKind = "outflow" | "inflow" | "spending" | "overflow";

export interface PortDefinition {
	kind: PortKind;
	dir: PortDirection;
	/** X offset as fraction of node width (0–1) */
	xFrac: number;
	/** Y offset: 0 = top, 1 = bottom */
	yFrac: number;
	color: string;
	/** Which port kinds this output can wire to */
	connectsTo?: PortKind[];
	/** For side-mounted ports (overflow lips) */
	side?: "left" | "right";
}

/** Single source of truth for port positions, colors, and connectivity rules. */
export const PORT_DEFS: Record<FlowNode["type"], PortDefinition[]> = {
	source: [
		{ kind: "outflow", dir: "out", xFrac: 0.75, yFrac: 1, color: "#10b981", connectsTo: ["inflow"] },
	],
	funnel: [
		{ kind: "inflow",   dir: "in",  xFrac: 0.5, yFrac: 0,    color: "#60a5fa" },
		{ kind: "overflow", dir: "out", xFrac: 0.08, yFrac: 0.08, color: "#f59e0b", connectsTo: ["inflow"], side: "left" },
		{ kind: "overflow", dir: "out", xFrac: 0.92, yFrac: 0.08, color: "#f59e0b", connectsTo: ["inflow"], side: "right" },
		{ kind: "spending", dir: "out", xFrac: 0.5, yFrac: 1,    color: "#8b5cf6", connectsTo: ["inflow"] },
	],
	outcome: [
		{ kind: "inflow",   dir: "in",  xFrac: 0.5, yFrac: 0, color: "#60a5fa" },
		{ kind: "overflow", dir: "out", xFrac: 0.5, yFrac: 1, color: "#f59e0b", connectsTo: ["inflow"] },
	],
};
