import { describe, expect, it } from "vitest";

import {
  resolveTargetCustomer,
  TARGET_CUSTOMER_REQUIRED_MESSAGE,
} from "@/lib/reports/target-customer";
import type { Customer } from "@/lib/types";

/**
 * 確定期間KPIの「対象顧客をどう決めるか」（指示書AK ★段階6★ / §2-1 の決定表）。
 *
 * ★★何を守るためのテストか★★
 *  - ★★候補が2つ以上のときに「静かに1社を選ぶ」ことをしない★★（★落とし穴6★。D-133）—
 *    ★静かに選ぶ実装は例外もテスト失敗も出さない★ので、ここで固定しておく以外に検出手段が無い
 *  - ★`customer_id` が明示されたら顧客マスタを見ない（存在確認をしない）★（期待値表 6-9）
 *  - ★`group_id` の候補は「その傘下だけ」★（別ホールディングスの顧客を混ぜない）
 *
 * ★ルート（HTTPステータス・`details`）側は
 *   `app/api/reports/__tests__/route.test.ts` の「段階6 — 対象顧客の決定」が見る★。
 */

/** 顧客マスタ1行（`db.customers()` の形。★`group_id` は API の形＝`null` 可★。D-011） */
function customer(id: number, groupId: number | null): Customer {
  return { id, customer_name: `屋号${id}`, group_id: groupId };
}

const NONE = { groupId: null, customerId: null };

describe("resolveTargetCustomer（指示書AK §2-1 の決定表）", () => {
  it("customer_id 指定 → その顧客（★顧客マスタを見ない＝存在確認をしない★。6-9）", () => {
    // ★マスタが空でも、存在しないIDでも、そのまま通す★
    expect(resolveTargetCustomer([], { groupId: null, customerId: 999 })).toEqual({
      ok: true,
      customerId: 999,
    });
  });

  // ★表9（指示書BB A17・D15・D-182）★ — customer_id と group_id の両方は AND（★AK §2-1 の決定表1行目「customer_id が勝つ」を上書き★）。
  //   顧客マスタ: 顧客1（group 1）・顧客2（group 2）・顧客3（group 1）・顧客4（group なし）
  describe("customer_id と group_id の同時指定は AND（表9）", () => {
    const customers = [customer(1, 1), customer(2, 2), customer(3, 1), customer(4, null)];

    it("K1: customer_id=2 だけ → 顧客2（存在確認しない）", () => {
      expect(resolveTargetCustomer(customers, { groupId: null, customerId: 2 })).toEqual({ ok: true, customerId: 2 });
    });

    it("K2: customer_id=2・group_id=2（傘下）→ 顧客2", () => {
      expect(resolveTargetCustomer(customers, { groupId: 2, customerId: 2 })).toEqual({ ok: true, customerId: 2 });
    });

    it("★K3: customer_id=2・group_id=1（傘下でない）→ 該当なし（customerId: null → 200・空）★", () => {
      expect(resolveTargetCustomer(customers, { groupId: 1, customerId: 2 })).toEqual({ ok: true, customerId: null });
    });

    it("K4: customer_id=4（グループなし）・group_id=1 → 該当なし", () => {
      expect(resolveTargetCustomer(customers, { groupId: 1, customerId: 4 })).toEqual({ ok: true, customerId: null });
    });

    it("K5: customer_id=999（無い）・group_id=1 → 該当なし", () => {
      expect(resolveTargetCustomer(customers, { groupId: 1, customerId: 999 })).toEqual({ ok: true, customerId: null });
    });

    it("★K7: customer_id=1・group_id=1（傘下2社）→ 顧客1（422 にしない。顧客が名指しされている）★", () => {
      expect(resolveTargetCustomer(customers, { groupId: 1, customerId: 1 })).toEqual({ ok: true, customerId: 1 });
    });

    it("K8: customer_id なし・group_id=1（傘下2社）→ 今どおり決まらない（候補 [1, 3]）", () => {
      expect(resolveTargetCustomer(customers, { groupId: 1, customerId: null })).toEqual({
        ok: false,
        candidateCustomerIds: [1, 3],
      });
    });
  });

  it("group_id 指定・傘下1社 → その顧客（6-6）", () => {
    const customers = [customer(1, 1), customer(2, 2), customer(3, null)];
    expect(resolveTargetCustomer(customers, { groupId: 2, customerId: null })).toEqual({
      ok: true,
      customerId: 2,
    });
  });

  it("★★group_id 指定・傘下2社 → 定まらない。候補は傘下だけ★★（6-7）", () => {
    const customers = [customer(1, 1), customer(2, 1), customer(3, 2)];
    expect(resolveTargetCustomer(customers, { groupId: 1, customerId: null })).toEqual({
      ok: false,
      candidateCustomerIds: [1, 2],
    });
  });

  it("★group_id 指定・傘下0社 → 定まらない（候補は空配列）★（★指示書に明記が無く、起草者が決めた★）", () => {
    const customers = [customer(1, 1)];
    expect(resolveTargetCustomer(customers, { groupId: 9, customerId: null })).toEqual({
      ok: false,
      candidateCustomerIds: [],
    });
  });

  it("どちらも未指定・顧客が1社だけ → その顧客（★P1 はここ★。6-3）", () => {
    expect(resolveTargetCustomer([customer(7, null)], NONE)).toEqual({
      ok: true,
      customerId: 7,
    });
  });

  it("★★どちらも未指定・顧客が2社 → 定まらない（★静かに1社を選ばない★）★★（6-4 / 6-5）", () => {
    const customers = [customer(1, 1), customer(2, 2)];
    expect(resolveTargetCustomer(customers, NONE)).toEqual({
      ok: false,
      candidateCustomerIds: [1, 2],
    });
  });

  it("★どちらも未指定・顧客が0社 → 定まらない★（マスタが空のときに何かを選ばない）", () => {
    expect(resolveTargetCustomer([], NONE)).toEqual({
      ok: false,
      candidateCustomerIds: [],
    });
  });

  it("★`group_id = null`（ホールディングスなし）の顧客は group_id 指定に当たらない★（D-011）", () => {
    const customers = [customer(1, null), customer(2, 1)];
    // ★「所属なしの顧客だけを引く」経路はそもそも存在しない★（API は 1 以上しか受け付けない）
    expect(resolveTargetCustomer(customers, { groupId: 1, customerId: null })).toEqual({
      ok: true,
      customerId: 2,
    });
  });

  it("★422 の文言は指示書AK §2-1 の原文★（言い換えない）", () => {
    expect(TARGET_CUSTOMER_REQUIRED_MESSAGE).toBe(
      "顧客またはグループを指定してください。複数の顧客のデータを合算した数値は出せません。"
    );
  });
});
