/**
 * GET /reports/error-breakdown — エラー種別の内訳（発生件数の降順・生値。D-077）
 *
 * 形は `app/api/ds-alerts/route.ts` に合わせている。
 * 仕様の正は `d-watch-api.yaml` の /reports/error-breakdown。
 * `type` は `robot_error_reports.error_type` の生値。サーバ側で変換しない（D-077）。
 */
import { NextResponse } from "next/server";
import { db } from "@/lib/db";
import { resolveFacilityIdsByMasters } from "@/lib/facilities/resolve-by-master";
import {
  parseReportQuery,
  selectErrorBreakdownRows,
  sortErrorBreakdown,
  toReportDbQuery,
} from "@/lib/reports/query";
import { withRequestId } from "@/lib/logger";
import { logApiError } from "@/lib/logger/api";
import type {
  ApiError,
  ErrorBreakdownItem,
  ErrorBreakdownRow,
} from "@/lib/types";

const ROUTE = "/api/reports/error-breakdown";

function errorResponse(error: ApiError, status: number) {
  return NextResponse.json(error, { status });
}

/**
 * ★meta を返さない（一覧APIの例外。D-088で再判断）★
 *   CLAUDE.md §9.3 は「一覧APIは必ず meta を返す」としているが、本エンドポイントは
 *   **意図的に meta を返さない**。理由: エラー種別の内訳は集計結果であり全件返す。
 *   ページングが要るほどの種別数にはならない見込み（limit パラメータも無い）。
 *   YAML の /reports/error-breakdown も `{ items }` のみで定義済み。
 *   `ListResponse<T>` を使わないのはこの理由（型を合わせるために meta を捏造しない）。
 *   ★生値方針（D-077）では種別数が固定されない。実データで数十に膨らむ可能性があるため、
 *   実DB接続後に件数を実測して再判断すること（D-088）★
 */
interface ErrorBreakdownResponse {
  items: ErrorBreakdownItem[];
}

export async function GET(request: Request) {
  return withRequestId(request, async () => {
    const { searchParams } = new URL(request.url);
    // `parseReportQuery` は /reports/* 共通なので status / facility_name / serial / limit も
    // 解釈するが、本エンドポイントにそれらのパラメータは存在しない。使わないフィールドは
    // 単に無視する（period / year / month / week の検証だけが必要）。
    const parsed = parseReportQuery(searchParams);
    if (!parsed.ok) {
      return errorResponse(parsed.error, parsed.status);
    }

    let rows: ErrorBreakdownRow[];
    try {
      // ★★期間を SQL に降ろす★★（指示書AC 段階5）— ★`parseReportQuery()` を通った値を渡す★。
      //   ★★`selectErrorBreakdownRows()` / `sortErrorBreakdown()` は残す★★（指示書AC C-5）。
      //   ★★分類（`group_id` / `customer_id`）は施設IDの配列に解決してから渡す★★
      //   （指示書AK 段階4b §7-3。★`facility_error_summaries` を `facility_id` で
      //   絞っていなかった D-133 申し送り③の解消★）— ★`null` = 絞らない / `[]` = 0件★。
      //   ★`rate` の分母も絞ったあとの母集団になる★（「この屋号のエラーのうち何%」）。
      rows = await db.errorBreakdown(
        toReportDbQuery(parsed.query, await resolveFacilityIdsByMasters(parsed.query))
      );
    } catch (e) {
      const body: ApiError = {
        error: {
          code: "internal_error",
          message: "データの取得に失敗しました",
          details: null,
        },
      };
      logApiError({ route: ROUTE, method: "GET", body, status: 500, err: e });
      return errorResponse(body, 500);
    }

    // ここから下は純粋な絞り込み・並べ替え。すべて try の外
    // （`app/api/ds-alerts/route.ts` と同じ方針）。
    const inPeriod: ErrorBreakdownItem[] = selectErrorBreakdownRows(
      rows,
      parsed.query
    );
    const items = sortErrorBreakdown(inPeriod);

    const body: ErrorBreakdownResponse = { items };
    return NextResponse.json(body);
  });
}
