/**
 * 施設別パフォーマンスの「取得 → 絞り込み → 並べ替え → 連続日数の上限処理」（D-163）
 *
 * ★★一覧（`GET /reports/facility-performance`）と CSV（`GET /reports/facility-performance/export`）の
 *   両方がこの1本を呼ぶ★★ — ★片方だけ直すと、画面の表と CSV の中身が食い違います★
 *   （例外もテスト失敗も出ない壊れ方。`/clean-logs` と `/clean-logs/export` が
 *   同じ引数を渡すことにしているのと同じ理由。指示書AC 段階2 D-6）。
 *
 * ★`limit` はここでは適用しない★ — 一覧は戻り値を `slice(0, limit)` し、
 *   CSV は全件を出す（画面の「全施設表示」の200件上限に縛られない。D-163）。
 *
 * ★DB の例外はそのまま投げる★ — 500 にするか（とログを出すか）はルートが決める。
 */
import { CONSECUTIVE_DAYS_DISPLAY } from "@/lib/config";
import { db } from "@/lib/db";
import { intersectFacilityIds } from "@/lib/facilities/intersect-ids";
import { resolveFacilityIdsByMasters } from "@/lib/facilities/resolve-by-master";
import { resolveFacilityIdsByName } from "@/lib/facilities/resolve-by-name";
import {
  capFacilityPerformance,
  filterFacilityPerformanceByName,
  filterFacilityPerformanceBySerial,
  filterFacilityPerformanceByStatus,
  selectFacilityPerformanceRows,
  sortFacilityPerformance,
  toReportDbQuery,
  type ReportQuery,
} from "@/lib/reports/query";
import { loadConsecutiveDaysMax } from "@/lib/settings/display-limits";
import type { FacilityPerformance } from "@/lib/types";

/**
 * 絞り込み・並べ替え・連続日数の上限処理まで済ませた ★全件★ を返す（`limit` は見ない）。
 *
 * 並び順は稼働率の昇順（ワースト順）・同値は facility_id の昇順・null は最後
 * （`sortFacilityPerformance()`。`d-watch-api.yaml` の /reports/facility-performance）。
 */
export async function loadFacilityPerformance(
  query: ReportQuery
): Promise<FacilityPerformance[]> {
  // ★表示上限（指示書AF 段階6）★ — 設定が読めないだけで一覧を 500 にしない。
  //   ★型注釈 `: number` が要る★（`CONSECUTIVE_DAYS_DISPLAY` は `as const` でリテラル型）
  let maxDays: number = CONSECUTIVE_DAYS_DISPLAY.defaultMax;
  try {
    maxDays = await loadConsecutiveDaysMax();
  } catch {
    // 既定値のまま続行する
  }

  // ★★施設名の照合はアプリ側で施設IDに解決してから SQL に渡す★★（指示書AC C-1 / 段階5。
  //   ★段階2（`/clean-logs`）で確定した作法をそのまま真似る。新しい書き方を発明しない★）—
  //   ★記号（中点等）を無視する照合は LIKE では書けない★（照合順序でも無理。実測済み）。
  //   ★★戻り値の `null` と `[]` は別物★★: `null` = 施設名の条件なし（全施設）/
  //   `[]` = ★照合したが1件も当たらなかった（＝0件）★。
  //   ★★施設名の絞り込みを持つレポートAPIはここだけ★★（`d-watch-api.yaml` の
  //   `/reports/facility-performance` と、その CSV の `/export` にだけ `facility_name` がある）。
  //   ★`serial` は据え置き＝メモリ絞り込みのまま★（索引が効かず利得が薄い。C-1）。
  //   ★★分類（`group_id` / `customer_id`）とは**積集合（AND）**を取る★★
  //   （指示書AK §6-2 / 段階4b）— ★どちらか片方を捨てないこと★。
  //   ★積が空なら `[]` ＝ 0件★（★`null` にすると条件ごと消えて全件表示に化ける★。
  //   落とし穴2。例外もテスト失敗も出ない）。
  const [byName, byMasters] = await Promise.all([
    resolveFacilityIdsByName(query.facilityName),
    resolveFacilityIdsByMasters(query),
  ]);
  const rows = await db.facilityPerformance(
    toReportDbQuery(query, intersectFacilityIds(byName, byMasters))
  );

  // ここから下は純粋な絞り込み・並べ替え。
  const inPeriod: FacilityPerformance[] = selectFacilityPerformanceRows(rows, query);
  const filtered = filterFacilityPerformanceBySerial(
    filterFacilityPerformanceByName(
      filterFacilityPerformanceByStatus(inPeriod, query.status),
      query.facilityName
    ),
    query.serial
  );
  const sorted = sortFacilityPerformance(filtered);

  // ★表示上限は絞り込み・並べ替えの**後**にかける★（指示書AF 段階6-2）
  //   件数（`meta.total`）も `status` の判定も上限とは無関係（上限は表示のためだけ）。
  //   ★1行ずつの写像なので、`limit` で切る前にかけても後にかけても結果は同じ★（D-163）。
  return capFacilityPerformance(sorted, maxDays);
}
