import { getPropertyId, formatPropertyPath, executeReport } from "../../client.js";
import { periodToDateRange } from "../../utils/date.js";
import { formatPercentageFromDecimal, calculatePercentage } from "../../utils/percentage.js";
import type {
GetTrafficSourcesInput,
GetTrafficSourcesOutput,
TrafficSource,
} from "../../types.js";
/**
* 流入元の分析
*/
export async function getTrafficSources(
input: GetTrafficSourcesInput
): Promise<GetTrafficSourcesOutput> {
const propertyId = getPropertyId(input.propertyId);
const property = formatPropertyPath(propertyId);
const dateRange = periodToDateRange(input.period);
// groupBy に応じてディメンションを選択
const dimensionMap: Record<string, string> = {
channel: "sessionDefaultChannelGroup",
source: "sessionSource",
medium: "sessionMedium",
sourceMedium: "sessionSourceMedium",
campaign: "sessionCampaignName",
};
const dimension = dimensionMap[input.groupBy] || "sessionDefaultChannelGroup";
const response = await executeReport({
property,
dateRanges: [dateRange],
dimensions: [{ name: dimension }],
metrics: [
{ name: "sessions" },
{ name: "totalUsers" },
{ name: "bounceRate" },
],
orderBys: [{ metric: { metricName: "sessions" }, desc: true }],
limit: 20,
});
// 合計セッション数を取得
const totalSessions =
response.totals?.[0]?.metricValues?.[0]?.value
? parseFloat(response.totals[0].metricValues[0].value)
: 0;
const sources: TrafficSource[] = [];
for (const row of response.rows || []) {
const dimensionValues = row.dimensionValues || [];
const metricValues = row.metricValues || [];
const getValue = (index: number): number => {
const value = metricValues[index]?.value;
return value ? parseFloat(value) : 0;
};
const sessions = Math.round(getValue(0));
sources.push({
name: dimensionValues[0]?.value || "(不明)",
sessions,
users: Math.round(getValue(1)),
percentage: calculatePercentage(sessions, totalSessions),
bounceRate: formatPercentageFromDecimal(getValue(2)),
});
}
return { sources };
}