/**
 * CRUD Server Action 팩토리
 *
 * 정형적인 CRUD actions.ts 파일의 보일러플레이트를 제거합니다.
 * executeServerAction 위에 한 단계 더 추상화하여
 * getList / getById / create / update / remove / bulkDelete / reorder 함수를 자동 생성합니다.
 *
 * 주의: 이 파일은 'use server'가 아닙니다.
 * 각 도메인의 actions.ts ('use server')에서 import하여 사용합니다.
 *
 * @example
 * ```typescript
 * // RankManagement/actions.ts
 * 'use server';
 * const service = createCrudService<PositionApiData, Rank>({
 *   basePath: '/api/v1/positions',
 *   transform: (api) => ({ id: api.id, name: api.name, ... }),
 *   entityName: '직급',
 *   defaultQueryParams: { type: 'rank' },
 *   defaultCreateBody: { type: 'rank' },
 * });
 * export async function getRanks(params?) { return service.getList(params); }
 * export async function getRankById(id) { return service.getById(id); }
 * ```
 */

import { executeServerAction, type ActionResult } from './execute-server-action';
import { isNextRedirectError } from '@/lib/utils/redirect-error';

// ===== 설정 타입 =====
export interface CrudServiceConfig<TApi, TFrontend> {
  /** API 경로 (예: '/api/v1/positions') */
  basePath: string;
  /** API → Frontend 데이터 변환 함수 */
  transform: (apiData: TApi) => TFrontend;
  /** 엔티티 한글명 (에러 메시지용, 예: '직급') */
  entityName: string;
  /** 목록 조회 시 기본 쿼리 파라미터 (예: { type: 'rank' }) */
  defaultQueryParams?: Record<string, string>;
  /** 생성 시 body에 추가할 기본값 (예: { type: 'rank' }) */
  defaultCreateBody?: Record<string, unknown>;
  /** 수정 시 HTTP 메서드 (기본: 'PUT') */
  updateMethod?: 'PUT' | 'PATCH';
}

// ===== 서비스 반환 타입 =====
export interface CrudService<TFrontend> {
  getList(params?: {
    is_active?: boolean;
    q?: string;
  }): Promise<ActionResult<TFrontend[]>>;

  getById(id: number | string): Promise<ActionResult<TFrontend>>;

  create(body: Record<string, unknown>): Promise<ActionResult<TFrontend>>;

  update(
    id: number | string,
    body: Record<string, unknown>
  ): Promise<ActionResult<TFrontend>>;

  remove(id: number | string): Promise<ActionResult>;

  bulkDelete(ids: (number | string)[]): Promise<ActionResult>;

  reorder(
    items: { id: number; sort_order: number }[]
  ): Promise<ActionResult>;
}

// ===== 팩토리 함수 =====
export function createCrudService<TApi, TFrontend>(
  config: CrudServiceConfig<TApi, TFrontend>
): CrudService<TFrontend> {
  const {
    basePath,
    transform,
    entityName,
    defaultQueryParams,
    defaultCreateBody,
    updateMethod = 'PUT',
  } = config;

  // API URL은 호출 시점에 resolve (SSR 안전)
  const getBaseUrl = () => `${process.env.NEXT_PUBLIC_API_URL}${basePath}`;

  return {
    async getList(params) {
      const searchParams = new URLSearchParams();
      if (defaultQueryParams) {
        Object.entries(defaultQueryParams).forEach(([k, v]) =>
          searchParams.set(k, v)
        );
      }
      if (params?.is_active !== undefined) {
        searchParams.set('is_active', params.is_active.toString());
      }
      if (params?.q) {
        searchParams.set('q', params.q);
      }

      return executeServerAction({
        url: `${getBaseUrl()}?${searchParams.toString()}`,
        transform: (data: TApi[]) => data.map(transform),
        errorMessage: `${entityName} 목록 조회에 실패했습니다.`,
      });
    },

    async getById(id) {
      return executeServerAction({
        url: `${getBaseUrl()}/${id}`,
        transform,
        errorMessage: `${entityName} 조회에 실패했습니다.`,
      });
    },

    async create(body) {
      return executeServerAction({
        url: getBaseUrl(),
        method: 'POST',
        body: { ...defaultCreateBody, ...body },
        transform,
        errorMessage: `${entityName} 생성에 실패했습니다.`,
      });
    },

    async update(id, body) {
      return executeServerAction({
        url: `${getBaseUrl()}/${id}`,
        method: updateMethod,
        body,
        transform,
        errorMessage: `${entityName} 수정에 실패했습니다.`,
      });
    },

    async remove(id) {
      return executeServerAction({
        url: `${getBaseUrl()}/${id}`,
        method: 'DELETE',
        errorMessage: `${entityName} 삭제에 실패했습니다.`,
      });
    },

    async bulkDelete(ids) {
      try {
        const results = await Promise.all(ids.map((id) =>
          executeServerAction({
            url: `${getBaseUrl()}/${id}`,
            method: 'DELETE',
            errorMessage: `${entityName} 삭제에 실패했습니다.`,
          })
        ));
        const failed = results.filter((r) => !r.success);
        if (failed.length > 0) {
          return { success: false, error: `${failed.length}개 ${entityName} 삭제에 실패했습니다.` };
        }
        return { success: true };
      } catch (error) {
        if (isNextRedirectError(error)) throw error;
        return { success: false, error: `${entityName} 일괄 삭제에 실패했습니다.` };
      }
    },

    async reorder(items) {
      return executeServerAction({
        url: `${getBaseUrl()}/reorder`,
        method: 'PUT',
        body: { items },
        errorMessage: '순서 변경에 실패했습니다.',
      });
    },
  };
}

// ActionResult 재export (actions.ts에서 import 편의)
export type { ActionResult } from './execute-server-action';
