/**
 * GET /ds-alerts で使うクエリ処理。
 * 仕様の正は `d-watch-api.yaml` の /ds-alerts。ソート順は D-052と同じ規則。
 */
import { parseMasterIdFilters } from "@/lib/api/master-id";
import { fail, type QueryParseResult } from "@/lib/api/query-result";
import { PAGINATION } from "@/lib/config";
import type { DsAlert, DsAlertStatusFilter, DsAlertTypeFilter } from "@/lib/types";

const TYPE_FILTERS: readonly DsAlertTypeFilter[] = [
  "all",
  "security_off",
  "disconnected",
];
const STATUS_FILTERS: readonly DsAlertStatusFilter[] = ["open", "all", "done"];

export interface DsAlertQuery {
  type: DsAlertTypeFilter;
  status: DsAlertStatusFilter;
  /**
   * ホールディングス（`groups.id`）で絞り込み。★`null` = 絞らない★（指示書AK 段階2）。
   * ★`customerId` と同時に指定されたら AND★（`d-watch-api.yaml` の `GroupId`）。
   */
  groupId: number | null;
  /** 顧客（`customers.id`）で絞り込み。★`null` = 絞らない★ */
  customerId: number | null;
  page: number;
  perPage: number;
}

function toInt(value: string | null, fallback: number): number {
  if (!value) return fallback;
  const n = Number.parseInt(value, 10);
  return Number.isNaN(n) ? fallback : n;
}

/**
 * クエリパラメータをパースする。
 * 不正な値があれば `{ ok: false }` を返す（`error` / `status` をそのまま422応答に使う。
 * どのパラメータが不正かは `error.error.details` に入る）。
 * ★group_id / customer_id を読む（指示書AK 段階2。D-053 の「受け取っても無視する」は解除）★
 *   検証は `parseMasterIdFilters()`（`lib/api/master-id.ts`）の1本に任せる。
 *   ★`Number.parseInt()` で書き直さないこと★（`1abc` が `1` として通る。D-123）。
 *
 * page / per_page は不正値でも失敗させず、既定値・上限へ丸める（/clean-logs と同じ挙動）。
 */
export function parseDsAlertQuery(
  searchParams: URLSearchParams
): QueryParseResult<DsAlertQuery> {
  const typeRaw = searchParams.get("type") ?? "all";
  if (!TYPE_FILTERS.includes(typeRaw as DsAlertTypeFilter)) {
    return fail(422, "validation_failed", "typeの値が不正です", {
      type: [`${TYPE_FILTERS.join(" / ")} のいずれかを指定してください`],
    });
  }

  const statusRaw = searchParams.get("status") ?? "open";
  if (!STATUS_FILTERS.includes(statusRaw as DsAlertStatusFilter)) {
    return fail(422, "validation_failed", "statusの値が不正です", {
      status: [`${STATUS_FILTERS.join(" / ")} のいずれかを指定してください`],
    });
  }

  const masters = parseMasterIdFilters(searchParams);
  if (!masters.ok) return masters;

  const page = Math.max(1, toInt(searchParams.get("page"), 1));
  const perPage = Math.min(
    PAGINATION.maxPerPage,
    Math.max(1, toInt(searchParams.get("per_page"), PAGINATION.defaultPerPage))
  );

  return {
    ok: true,
    query: {
      type: typeRaw as DsAlertTypeFilter,
      status: statusRaw as DsAlertStatusFilter,
      groupId: masters.query.groupId,
      customerId: masters.query.customerId,
      page,
      perPage,
    },
  };
}

/** alert_type のみで絞り込む */
export function filterDsAlertsByType(
  items: DsAlert[],
  type: DsAlertTypeFilter
): DsAlert[] {
  if (type === "all") return items;
  return items.filter((item) => item.alert_type === type);
}

/** open = 未対応+対応中（対応済みでない）。YAML定義通り */
export function filterDsAlertsByStatus(
  items: DsAlert[],
  status: DsAlertStatusFilter
): DsAlert[] {
  return items.filter((item) => {
    switch (status) {
      case "open":
        return item.resolution_status !== "done";
      case "done":
        return item.resolution_status === "done";
      case "all":
        return true;
    }
  });
}

/** detected_at の降順。同値のときは id の昇順で安定させる（D-052と同じ規則） */
export function sortDsAlerts(items: DsAlert[]): DsAlert[] {
  return [...items].sort((a, b) => {
    if (a.detected_at !== b.detected_at) {
      return a.detected_at < b.detected_at ? 1 : -1;
    }
    return a.id - b.id;
  });
}

export interface DsAlertSummary {
  pending: number;
  in_progress: number;
  done: number;
}

/**
 * デバイスの現況サマリ。
 *
 * ★summary はフリートの部分集合（日付・グループ・会社）で絞る。
 *   閲覧の絞り込み（q・status・type）では絞らない。★
 *   グループ・会社マスタ導入時は、ここに絞り込みを追加する（現在は D-053 で未実装）。
 *   この区別を崩すと、F-03 で起きた「既定表示で解消済みが常に0」と同じ不具合になる（D-054）。
 */
export function summarizeDsAlerts(items: DsAlert[]): DsAlertSummary {
  const pending = items.filter(
    (item) => item.resolution_status === "pending"
  ).length;
  const in_progress = items.filter(
    (item) => item.resolution_status === "in_progress"
  ).length;
  const done = items.filter((item) => item.resolution_status === "done").length;
  return { pending, in_progress, done };
}
