import 'server-only';
import { cache } from 'react';
import { getSessionAccessToken } from '@/lib/auth/dal';
import { BackendRequestError, backendFetch } from '@/lib/http/backend-fetch';
import type { AdminMenu } from '@/lib/domain/admin-menu';
import { toYesNo } from '@/lib/domain/admin-menu';
import type { AdminMenuValues } from '@/lib/domain/admin-menu-form';

/*
 * GET    /api/v1/mngr/menu/pagination   목록 (TB_SYS_MENU)
 * POST   /api/v1/mngr/menu              등록 — 어노테이션 없음 → form
 * PUT    /api/v1/mngr/menu/{menuId}     수정 — @RequestBody(JSON)
 * DELETE /api/v1/mngr/menu/{menuId}     삭제
 *
 * 이슈(백엔드, 보고함):
 * 1. `DELETE`의 `menuId`에 `@PathVariable`이 없어 경로값이 바인딩되지 않는다 → 항상 실패한다.
 * 2. 등록의 menuId 채번이 `MAX(menu_id) WHERE UP_MENU_ID = ?`라 상위별 최대값이다 → 자식이 없는
 *    메뉴에 처음 추가하면 이미 존재하는 번호가 나와 PK 충돌로 실패한다.
 * 3. `GET /{menuId}`는 경로변수 이름이 `userId`로 어긋나 있고 빈 VO로 조회한다 → 쓰지 않는다.
 *    수정 팝업의 초기값은 목록 응답에서 넘겨 채운다.
 * 4. `totalCount`가 현재 페이지 행 수다(다른 목록과 같은 PaginationUtil 결함).
 * 5. 새창여부에 해당하는 컬럼이 없다 — 화면은 기획대로 그리되 저장되지 않는다.
 */

const ADMIN_MENU_PATH = '/api/v1/mngr/menu';

// 기획이 "페이징 없이 전체 노출"이라 한 장으로 받는다.
const FETCH_LIMIT = 10_000;

function isRecord(value: unknown): value is Record<string, unknown> {
  return value !== null && typeof value === 'object';
}

function readString(source: Record<string, unknown>, key: string): string {
  const value = source[key];
  return typeof value === 'string' ? value : '';
}

function readNumber(source: Record<string, unknown>, key: string): number {
  const value = source[key];
  return typeof value === 'number' ? value : 0;
}

function toAdminMenu(raw: unknown): AdminMenu {
  if (!isRecord(raw)) {
    throw new Error('메뉴 응답 항목의 형식이 올바르지 않습니다.');
  }

  const id = readString(raw, 'menuId');
  if (!id) {
    throw new Error('메뉴 응답에 menuId가 없습니다.');
  }

  const parentId = readString(raw, 'upMenuId');

  return {
    id,
    parentId: parentId || null,
    name: readString(raw, 'menuName'),
    url: readString(raw, 'menuUrl'),
    description: readString(raw, 'menuExplan'),
    sortOrder: readNumber(raw, 'sortOrdr'),
    roleId: readString(raw, 'roleId'),
    roleName: readString(raw, 'roleNm'),
    isActive: readString(raw, 'useYn') !== 'N',
    isTopActive: readString(raw, 'topYn') === 'Y',
  };
}

export const fetchAdminMenus = cache(async (): Promise<AdminMenu[]> => {
  const accessToken = await getSessionAccessToken();

  const result = await backendFetch<unknown>(`${ADMIN_MENU_PATH}/pagination`, {
    method: 'GET',
    query: { pageIndex: 1, recordCountPerPage: FETCH_LIMIT },
    accessToken: accessToken ?? undefined,
    cache: 'no-store',
  });

  if (!result.ok) {
    throw new BackendRequestError(result);
  }

  const data = result.data;
  if (!isRecord(data) || !Array.isArray(data.list)) {
    throw new Error('메뉴 목록 응답의 형식이 올바르지 않습니다.');
  }

  return data.list.map(toAdminMenu);
});

function buildPayload(values: AdminMenuValues) {
  return {
    menuName: values.name,
    menuUrl: values.url,
    menuExplan: values.description,
    sortOrdr: values.sortOrder,
    roleId: values.roleId,
    useYn: toYesNo(values.isActive),
    topYn: toYesNo(values.isTopActive),
  };
}

export async function createAdminMenu(
  parentId: string,
  values: AdminMenuValues
): Promise<void> {
  const accessToken = await getSessionAccessToken();

  const result = await backendFetch<null>(ADMIN_MENU_PATH, {
    method: 'POST',
    form: { ...buildPayload(values), upMenuId: parentId },
    accessToken: accessToken ?? undefined,
    cache: 'no-store',
    canHaveNullData: true,
  });

  if (!result.ok) {
    throw new BackendRequestError(result);
  }
}

export async function updateAdminMenu(
  menuId: string,
  values: AdminMenuValues
): Promise<void> {
  const accessToken = await getSessionAccessToken();

  const result = await backendFetch<null>(
    `${ADMIN_MENU_PATH}/${encodeURIComponent(menuId)}`,
    {
      method: 'PUT',
      body: buildPayload(values),
      accessToken: accessToken ?? undefined,
      cache: 'no-store',
      canHaveNullData: true,
    }
  );

  if (!result.ok) {
    throw new BackendRequestError(result);
  }
}

export async function deleteAdminMenu(menuId: string): Promise<void> {
  const accessToken = await getSessionAccessToken();

  const result = await backendFetch<null>(
    `${ADMIN_MENU_PATH}/${encodeURIComponent(menuId)}`,
    {
      method: 'DELETE',
      accessToken: accessToken ?? undefined,
      cache: 'no-store',
      canHaveNullData: true,
    }
  );

  if (!result.ok) {
    throw new BackendRequestError(result);
  }
}
