import { getPropertyId, formatPropertyPath, executeReport } from "../../client.js";
import { periodToDateRange, getDayCount } from "../../utils/date.js";
import { roundToDecimal } from "../../utils/format.js";
import type {
GetHourlyTrafficInput,
GetHourlyTrafficOutput,
HourlyData,
} from "../../types.js";
/**
* 時間帯別のアクセス分析
*/
export async function getHourlyTraffic(
input: GetHourlyTrafficInput
): Promise<GetHourlyTrafficOutput> {
const propertyId = getPropertyId(input.propertyId);
const property = formatPropertyPath(propertyId);
const dateRange = periodToDateRange(input.period);
const dayCount = getDayCount(dateRange);
const response = await executeReport({
property,
dateRanges: [dateRange],
dimensions: [{ name: "hour" }],
metrics: [{ name: "totalUsers" }, { name: "screenPageViews" }],
orderBys: [{ dimension: { dimensionName: "hour" }, desc: false }],
limit: 24,
});
// 時間ごとのデータを初期化(0-23時)
const hourlyMap = new Map<number, { users: number; pageViews: number }>();
for (let i = 0; i < 24; i++) {
hourlyMap.set(i, { users: 0, pageViews: 0 });
}
// レスポンスからデータを収集
for (const row of response.rows || []) {
const hour = parseInt(row.dimensionValues?.[0]?.value || "0", 10);
const users = row.metricValues?.[0]?.value
? parseFloat(row.metricValues[0].value)
: 0;
const pageViews = row.metricValues?.[1]?.value
? parseFloat(row.metricValues[1].value)
: 0;
hourlyMap.set(hour, { users, pageViews });
}
// 平均を計算してHourlyData配列を作成
const hourlyData: HourlyData[] = [];
let maxUsers = 0;
let minUsers = Infinity;
for (let hour = 0; hour < 24; hour++) {
const data = hourlyMap.get(hour)!;
const avgUsers = roundToDecimal(data.users / dayCount);
const avgPageViews = roundToDecimal(data.pageViews / dayCount);
if (avgUsers > maxUsers) maxUsers = avgUsers;
if (avgUsers < minUsers) minUsers = avgUsers;
hourlyData.push({
hour,
avgUsers,
avgPageViews,
peakIndicator: false, // 後で設定
});
}
// ピーク判定の閾値(平均値の1.5倍以上)
const avgAllHours =
hourlyData.reduce((sum, h) => sum + h.avgUsers, 0) / 24;
const peakThreshold = avgAllHours * 1.5;
const quietThreshold = avgAllHours * 0.5;
// ピーク時間帯と閑散時間帯を特定
const peakHours: number[] = [];
const quietHours: number[] = [];
for (const data of hourlyData) {
if (data.avgUsers >= peakThreshold) {
data.peakIndicator = true;
peakHours.push(data.hour);
}
if (data.avgUsers <= quietThreshold) {
quietHours.push(data.hour);
}
}
return {
hourlyData,
peakHours,
quietHours,
};
}