jest.mock('drizzle/schema', () =>
  jest.requireActual('../../../../../drizzle/schema'),
);

import { MedicationStandardRepository } from './medication-standard.repository';

const queryResult = <T>(rows: T) => {
  const query: Record<string, jest.Mock | ((...args: any[]) => Promise<T>)> =
    {};
  for (const method of ['from', 'innerJoin', 'where', 'orderBy']) {
    query[method] = jest.fn(() => query);
  }
  query.then = (
    resolve: (value: T) => unknown,
    reject: (reason: unknown) => unknown,
  ) => Promise.resolve(rows).then(resolve, reject);
  return query;
};

describe('MedicationStandardRepository.getDosing30DayGroups', () => {
  const scopes: Array<
    [string, number | undefined, number | undefined, number | undefined]
  > = [
    ['일반회원', 1, undefined, undefined],
    ['B2C', undefined, 2, undefined],
    ['고객사', undefined, undefined, 3],
  ];

  it.each(scopes)(
    '%s 다중 진단을 붙여도 처방 건수와 30일 합계를 바꾸지 않는다',
    async (_scope, oddId, bodId, codId) => {
      const drizzle = {
        select: jest
          .fn()
          .mockReturnValueOnce(
            queryResult([
              {
                categoryName: '혈압강하제',
                efficacy: '혈압강하',
                treatStartDate: '2026-06-10',
                hospitalName: '가나다의원',
                drugName: '예시약',
                ingredients: '예시성분',
                oneDose: 1,
                dailyDosesNumber: 1,
                totalDosingDays: 30,
              },
              {
                categoryName: '혈압강하제',
                efficacy: '혈압강하',
                treatStartDate: '2026-06-12',
                hospitalName: '미매칭의원',
                drugName: '다른약',
                ingredients: '다른성분',
                oneDose: 1,
                dailyDosesNumber: 1,
                totalDosingDays: 0,
              },
            ]),
          )
          .mockReturnValueOnce(
            queryResult([
              {
                treatStartDate: '2026-06-10',
                hospitalName: '가나다의원',
                diseaseCode: ' I10 ',
                diseaseName: ' 본태성 고혈압 ',
              },
              {
                treatStartDate: '2026-06-10',
                hospitalName: '가나다의원',
                diseaseCode: 'I10',
                diseaseName: '본태성 고혈압',
              },
              {
                treatStartDate: '2026-06-10',
                hospitalName: '가나다의원',
                diseaseCode: 'E785',
                diseaseName: '고지혈증',
              },
              {
                treatStartDate: '2026-06-10',
                hospitalName: '가나다의원',
                diseaseCode: 'Z00',
                diseaseName: null,
              },
              {
                treatStartDate: '2026-06-10',
                hospitalName: '가나다의원',
                diseaseCode: null,
                diseaseName: '단독 진단명',
              },
              {
                treatStartDate: '2026-06-10',
                hospitalName: '가나다의원',
                diseaseCode: ' ',
                diseaseName: ' ',
              },
              {
                treatStartDate: '2026-06-11',
                hospitalName: '가나다의원',
                diseaseCode: 'J00',
                diseaseName: '감기',
              },
              {
                treatStartDate: '2026-06-10',
                hospitalName: '다른의원',
                diseaseCode: 'M54',
                diseaseName: '등통증',
              },
            ]),
          ),
      };
      const repository = new MedicationStandardRepository(drizzle as any);

      const result = await repository.getDosing30DayGroups(oddId, bodId, codId);

      expect(result).toHaveLength(1);
      expect(result[0].totalDosingDays).toBe(30);
      expect(result[0].records).toHaveLength(2);
      expect(result[0].records[0]).toMatchObject({
        treatStartDate: '2026-06-12',
        diagnoses: [],
      });
      expect(result[0].records[1].diagnoses).toEqual([
        { diseaseCode: 'I10', diseaseName: '본태성 고혈압' },
        { diseaseCode: 'E785', diseaseName: '고지혈증' },
        { diseaseCode: 'Z00', diseaseName: null },
        { diseaseCode: null, diseaseName: '단독 진단명' },
      ]);
      expect(drizzle.select).toHaveBeenCalledTimes(2);
    },
  );

  it('30일 미만이면 기본진료를 추가 조회하지 않는다', async () => {
    const drizzle = {
      select: jest.fn().mockReturnValueOnce(
        queryResult([
          {
            categoryName: '혈압강하제',
            efficacy: '혈압강하',
            treatStartDate: '2026-06-10',
            hospitalName: '가나다의원',
            drugName: '예시약',
            ingredients: '예시성분',
            oneDose: 1,
            dailyDosesNumber: 1,
            totalDosingDays: 29,
          },
        ]),
      ),
    };
    const repository = new MedicationStandardRepository(drizzle as any);

    await expect(repository.getDosing30DayGroups(1)).resolves.toEqual([]);
    expect(drizzle.select).toHaveBeenCalledTimes(1);
  });

  //* 상병별 판정 입력(2026-10-13 고객사 「한 상병 내에서 30일 이상」) — 약효분류 합계로 미리 거르면 여러 분류에
  //* 나뉜 한 상병의 처방이 빠지거나 일수가 덜 센다. 판정 배치는 0 을 넘겨 분류 컷 없이 받고, 30일 컷은 상병별로 한다.
  it('minTotalDays 를 0 으로 주면 30일 미만 분류도 돌려준다 — 상병별 판정 입력', async () => {
    const drizzle = {
      select: jest
        .fn()
        .mockReturnValueOnce(
          queryResult([
            {
              categoryName: '혈압강하제',
              efficacy: '혈압강하',
              treatStartDate: '2026-06-10',
              hospitalName: '가나다의원',
              drugName: '예시약',
              ingredients: '예시성분',
              oneDose: 1,
              dailyDosesNumber: 1,
              totalDosingDays: 29,
            },
          ]),
        )
        .mockReturnValueOnce(queryResult([])),
    };
    const repository = new MedicationStandardRepository(drizzle as any);

    const groups = await repository.getDosing30DayGroups(1, undefined, undefined, 0);
    expect(groups).toHaveLength(1);
    expect(groups[0]).toMatchObject({ categoryName: '혈압강하제', totalDosingDays: 29 });
    //* 화면 라우트(기본값)는 그대로 30일 컷이다.
    expect(drizzle.select).toHaveBeenCalledTimes(2);
  });
});
