/**
 * Server Action 공통 실행 유틸리티
 *
 * 82개 action.ts 파일에서 반복되는 보일러플레이트를 제거합니다:
 * - try/catch + isNextRedirectError
 * - serverFetch 호출 + 에러 체크
 * - response.json() + success 검증
 * - 일관된 ActionResult 반환
 *
 * @example
 * ```typescript
 * // Before: ~20줄
 * export async function getRanks() {
 *   try {
 *     const { response, error } = await serverFetch(url, { method: 'GET' });
 *     if (error) return { success: false, error: error.message, __authError: error.__authError };
 *     if (!response) return { success: false, error: '...' };
 *     const result = await response.json();
 *     if (!response.ok || !result.success) return { success: false, error: result.message };
 *     return { success: true, data: result.data.map(transform) };
 *   } catch (error) {
 *     if (isNextRedirectError(error)) throw error;
 *     return { success: false, error: '...' };
 *   }
 * }
 *
 * // After: ~5줄
 * export async function getRanks() {
 *   return executeServerAction({
 *     url: `${API_URL}/api/v1/positions?type=rank`,
 *     transform: (data: PositionApiData[]) => data.map(transformApiToFrontend),
 *     errorMessage: '직급 목록 조회에 실패했습니다.',
 *   });
 * }
 * ```
 */

import { serverFetch } from './fetch-wrapper';
import { isNextRedirectError } from '@/lib/utils/redirect-error';

// ===== 필드별 에러 타입 =====
export type FieldErrors = Record<string, string[]>;

// ===== 공통 반환 타입 =====
export interface ActionResult<T = unknown> {
  success: boolean;
  data?: T;
  error?: string;
  fieldErrors?: FieldErrors;
  __authError?: boolean;
}

// ===== 옵션 타입 =====
interface ExecuteOptions<TApi = unknown, TResult = TApi> {
  /** API URL (전체 경로) */
  url: string;
  /** HTTP 메서드 (기본: GET) */
  method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
  /** 요청 본문 (POST/PUT/PATCH) - FormData 또는 JSON-직렬화 가능 객체 */
  body?: unknown;
  /** API 응답 데이터 → 프론트엔드 타입 변환 함수 */
  transform?: (data: TApi) => TResult;
  /** 실패 시 기본 에러 메시지 */
  errorMessage?: string;
  /** fetch 캐시 설정 (기본: no-store) */
  cache?: RequestCache;
}

/**
 * Server Action 실행 유틸리티
 *
 * serverFetch 호출 → 에러 처리 → JSON 파싱 → transform 적용 → ActionResult 반환
 */
export async function executeServerAction<TApi = unknown, TResult = TApi>(
  options: ExecuteOptions<TApi, TResult>
): Promise<ActionResult<TResult>> {
  const {
    url,
    method = 'GET',
    body,
    transform,
    errorMessage = '처리에 실패했습니다.',
    cache = 'no-store',
  } = options;

  try {
    const fetchOptions: RequestInit & { cache?: RequestCache } = {
      method,
      cache,
    };

    if (body !== undefined) {
      fetchOptions.body = body instanceof FormData ? body : JSON.stringify(body);
    }

    const { response, error } = await serverFetch(url, fetchOptions);

    // serverFetch 에러 (네트워크, 403 등)
    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.__authError,
      };
    }

    // 응답 없음
    if (!response) {
      return { success: false, error: errorMessage };
    }

    // 204 No Content (DELETE 성공 등)
    if (response.status === 204) {
      return { success: true };
    }

    // JSON 파싱 (PHP trailing output + HTML 에러 페이지 안전 처리)
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    let result: any;
    try {
      const { safeResponseJson } = await import('./safe-json-parse');
      result = await safeResponseJson(response);
    } catch {
      const status = response.status;
      console.error(`[executeServerAction] JSON 파싱 실패 (${method} ${url}, status: ${status})`);
      return {
        success: false,
        error: status === 404
          ? '요청한 API를 찾을 수 없습니다.'
          : `서버 오류가 발생했습니다. (${status})`,
      };
    }

    // API 실패 응답
    if (!response.ok || !result.success) {
      let errorMsg = result.message || errorMessage;
      let fieldErrors: FieldErrors | undefined;

      // Laravel validation errors: { error: { code: 422, details: { field: ['msg'] } } }
      const details = result.error?.details;
      if (details && typeof details === 'object') {
        fieldErrors = details as FieldErrors;
        const validationErrors = Object.values(fieldErrors).flat().join(', ');
        if (validationErrors) errorMsg = validationErrors;
      }
      // fallback: { errors: { field: ['msg'] } } (Laravel 기본 형식)
      else if (result.errors && typeof result.errors === 'object') {
        fieldErrors = result.errors as FieldErrors;
        const validationErrors = Object.values(fieldErrors).flat().join(', ');
        if (validationErrors) errorMsg = validationErrors;
      }

      return {
        success: false,
        error: errorMsg,
        fieldErrors,
      };
    }

    // 성공 + transform
    if (transform && result.data !== undefined) {
      return { success: true, data: transform(result.data) };
    }

    // 성공 (data 없거나 transform 없음)
    return { success: true, data: result.data };
  } catch (error) {
    // Next.js redirect()는 다시 throw
    if (isNextRedirectError(error)) throw error;

    console.error(`[executeServerAction] ${method} ${url}:`, error);
    return { success: false, error: errorMessage };
  }
}
