/**
 * fixtures 版レポート4メソッドの絞り込み（指示書AC ★段階5★。段階2 D-5 の作法をそのまま真似る）。
 *
 * ★★`USE_FIXTURES` の true/false で件数が変わってはいけない★★（指示書AC 禁止事項6）。
 *   Prisma 版が SQL に降ろした条件（期間キー・施設ID）と ★同じ意味★ をここで再現します。
 *
 * ★絞り込み規則の「正」は `lib/reports/query.ts` の `selectXxxRows()` / `selectKpiRow()`★ —
 *   ここも Prisma 側もその ★写し★ です（指示書AC C-5）。★★あちらを外さないこと★★。
 *
 * ★DBアクセスを混ぜない純粋関数★（テストから直接呼べるようにするため。
 * `lib/db/fixture-clean-logs.ts` / `lib/db/fixture-prechecks.ts` と同じ流儀）。
 */
import type {
  FacilityPerformanceDbQuery,
  FacilityPerformanceRow,
  ReportDbQuery,
  ReportKpiDbQuery,
  ReportPeriodKey,
} from "@/lib/types";

/**
 * 行の期間キーが要求された期間と一致するか。
 *
 * ★`matchesPeriod()`（`lib/reports/query.ts`）と同じ4項目の単純比較★ —
 *   ★monthly も `week` を 0 で持つ（D-072）ので period による場合分けは要らない★。
 *   ★★あちらは private なので写してある★★（`lib/types` を経由しない import で
 *   ルート層とデータ層を結ぶより、同じ規則を2行書くほうが依存が素直）。
 *   ★規則が変わったら両方直すこと★ — ★どちらかだけ変えると、SQL 版だけ / fixtures 版だけが
 *   ずれ、`USE_FIXTURES` の切替で件数が変わります★（禁止事項6）。
 */
function matchesPeriod(row: ReportPeriodKey, query: ReportDbQuery): boolean {
  return (
    row.period === query.period &&
    row.year === query.year &&
    row.month === query.month &&
    row.week === query.week
  );
}

/**
 * 期間キーだけで絞る（`reportKpis()` / `continuousProblems()` / `errorBreakdown()` 用）。
 *
 * ★★前期（`shiftPeriod()` の1つ前）の行は返さない★★ — Prisma 版は「前期比」のために
 *   サマリを2行ぶん引きますが、★返すのは要求された期間の行だけ★（前期の値は
 *   `KpiValue.prev` の中に入って出る）。★fixtures も同じにすること★。
 */
export function filterFixtureReportRows<TRow extends ReportPeriodKey>(
  rows: readonly TRow[],
  query: ReportDbQuery
): TRow[] {
  return rows.filter((row) => matchesPeriod(row, query));
}

/**
 * 期間キー ＋ ★対象顧客★ で絞る（`reportKpis()` 用。指示書AK ★段階6★）。
 *
 * ★★Prisma 版が `customer_summaries` の `where` に `customer_id` を足したのと**同じ意味**★★ —
 *   ★`USE_FIXTURES` の true/false で数字が変わってはいけない★（禁止事項6）。
 *
 * ★★「絞らない」という選択肢は無い★★ — `ReportKpiDbQuery.customer_id` は必須で、
 *   ★顧客が決まらないときはデータ層を呼ばずに 422★（`resolveTargetCustomer()`。§2-1）。
 *   ★`facility_ids` の `null` / `[]` のような二択ではない★ので、ここに `!== null` の分岐は無い。
 *
 * ★該当が無ければ空配列★ — ★存在しない `customer_id` でも 404 にしない★
 *   （期待値表 6-9。ルート側が空のKPIを組み立てる）。
 *
 * ★★`query.facility_ids` はここでは使わない★★（指示書AL ★段階1★）—
 *   Prisma 版は ★当期（進行中の週・月）だけ★ この値で `clean_timetables` を絞るが、
 *   ★fixtures の KPI 行は当期ぶんも「顧客単位の集計値」として置いてある★
 *   （`lib/fixtures/reports.ts` の `reportKpis`。施設の次元を持たない）ので、
 *   ★同じ顧客から解決した施設IDで絞っても結果は変わらない★。
 *   ★★つまり `customer_id` だけで Prisma 版と同じ母集団になっている★★
 *   （＝ 存在しない顧客なら両方とも空。指示書AL 期待値表 1-3）。
 */
export function filterFixtureReportKpis<
  TRow extends ReportPeriodKey & { customer_id: number },
>(rows: readonly TRow[], query: ReportKpiDbQuery): TRow[] {
  return filterFixtureReportRows(rows, query).filter(
    (row) => row.customer_id === query.customer_id
  );
}

/**
 * 期間キー ＋ ★施設ID★ で絞る（`facilityPerformance()` / `continuousProblems()` 用）。
 *
 * ★★`facility_ids` の `null` と `[]` を Prisma 版と**同じ意味**で扱うこと★★（★罠9★）:
 *   - ★`null` → 施設で絞らない（全件）★
 *   - ★★`[]` → 0件を返す★★（★★`[]` を「条件なし」と読んで全件返す実装にしないこと★★ —
 *     `USE_FIXTURES` の true/false で件数が変わり、禁止事項6 に違反します）
 *
 * ★★`?.length` で分岐しないこと★★ — `[]` が「条件なし」に化けます（罠1と同じ形）。
 *
 * ★`item.facility_id` を持つ行型ならどれでも使える★（指示書AK 段階4b で
 *   `ContinuousProblemRow` にも要るようになったため一般化した）。
 *   ★`ErrorBreakdownRow` には使えない★ — ★あちらの `item` は施設をまたいで
 *   足し上げたあとの集計値で、施設の情報を持たない★（`errorBreakdown()` の注記）。
 */
export function filterFixtureRowsByFacility<
  TRow extends ReportPeriodKey & { item: { facility_id: number } },
>(rows: readonly TRow[], query: ReportDbQuery): TRow[] {
  const inPeriod = filterFixtureReportRows(rows, query);
  // ★★`!== null` で分岐すること★★（罠1 / 罠9）
  if (query.facility_ids === null) return inPeriod;
  const ids = new Set(query.facility_ids);
  return inPeriod.filter((row) => ids.has(row.item.facility_id));
}

/**
 * `facilityPerformance()` 用の別名（★既存の呼び出し側とテストのために残してある★）。
 * 中身は `filterFixtureRowsByFacility()` そのもの。
 */
export function filterFixtureFacilityPerformance(
  rows: readonly FacilityPerformanceRow[],
  query: FacilityPerformanceDbQuery
): FacilityPerformanceRow[] {
  return filterFixtureRowsByFacility(rows, query);
}
