// lib/api/index.ts
// API 클라이언트 배럴 익스포트

export { ApiClient, withTokenRefresh } from './client';
export { serverFetch } from './fetch-wrapper';
export { AUTH_CONFIG } from './auth/auth-config';

// 공용 API 타입 및 페이지네이션 유틸리티
export {
  toPaginationMeta,
  type PaginatedApiResponse,
  type PaginationMeta,
  type PaginatedResult,
  type SelectOption,
} from './types';

// 쿼리 파라미터 빌더 (신규 코드용)
export { buildQueryParams, buildApiUrl } from './query-params';

// 페이지네이션 조회 래퍼 (신규 코드용)
export { executePaginatedAction, type PaginatedActionResult } from './execute-paginated-action';

// 공용 룩업 헬퍼 (거래처/계좌 조회)
export {
  fetchVendorOptions,
  fetchBankAccountOptions,
  fetchBankAccountDetailOptions,
  type BankAccountOption,
} from './shared-lookups';

// 공통 코드 타입 및 유틸리티
export {
  toCommonCodeOptions,
  getCodeLabel,
  type CommonCode,
  type CommonCodeOption,
} from './common-codes';

// Server-side API 클라이언트
// 서버 액션에서 쿠키 기반 Bearer 토큰 자동 포함
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import { AUTH_CONFIG } from './auth/auth-config';
import { authenticatedFetch } from './authenticated-fetch';
import { isNextRedirectError } from '@/lib/utils/redirect-error';

/**
 * Server Actions 전용 API 클라이언트
 *
 * 특징:
 * - 쿠키에서 access_token 자동 읽기
 * - X-API-KEY + Bearer 토큰 자동 포함
 * - 401 발생 시 authenticatedFetch 게이트웨이를 통한 자동 갱신
 */
class ServerApiClient {
  private baseURL: string;
  private apiKey: string;

  constructor() {
    const apiUrl = AUTH_CONFIG.apiUrl.replace(/\/$/, '');
    this.baseURL = `${apiUrl}/api/v1`;
    this.apiKey = process.env.API_KEY || '';
  }

  /**
   * 쿠키에서 인증 헤더 생성 (async)
   */
  private async getAuthHeaders(token?: string): Promise<Record<string, string>> {
    const cookieStore = await cookies();
    const accessToken = token || cookieStore.get('access_token')?.value;

    return {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'X-API-KEY': this.apiKey,
      ...(accessToken ? { 'Authorization': `Bearer ${accessToken}` } : {}),
    };
  }

  /**
   * 토큰 쿠키 삭제 (인증 실패 시)
   */
  private async clearTokenCookies() {
    const cookieStore = await cookies();
    cookieStore.delete('access_token');
    cookieStore.delete('refresh_token');
    cookieStore.delete('token_refreshed_at');
    cookieStore.delete('is_authenticated');
  }

  /**
   * 새 토큰을 쿠키에 저장
   */
  private async setNewTokenCookies(tokens: {
    accessToken?: string;
    refreshToken?: string;
    expiresIn?: number;
  }) {
    const cookieStore = await cookies();
    const isProduction = process.env.NODE_ENV === 'production';

    if (tokens.accessToken) {
      cookieStore.set('access_token', tokens.accessToken, {
        httpOnly: true,
        secure: isProduction,
        sameSite: 'lax',
        path: '/',
        maxAge: tokens.expiresIn || 7200,
      });

      cookieStore.set('token_refreshed_at', Date.now().toString(), {
        httpOnly: false,
        secure: isProduction,
        sameSite: 'lax',
        path: '/',
        maxAge: 60,
      });
    }

    if (tokens.refreshToken) {
      cookieStore.set('refresh_token', tokens.refreshToken, {
        httpOnly: true,
        secure: isProduction,
        sameSite: 'lax',
        path: '/',
        maxAge: 604800,
      });
    }
  }

  /**
   * HTTP 요청 실행 (authenticatedFetch 게이트웨이를 통한 자동 갱신)
   */
  private async request<T>(
    endpoint: string,
    options?: RequestInit & { skipAuthRetry?: boolean }
  ): Promise<T> {
    try {
      const cookieStore = await cookies();
      const refreshToken = cookieStore.get('refresh_token')?.value;
      const headers = await this.getAuthHeaders();

      const url = `${this.baseURL}${endpoint}`;

      // authenticatedFetch 게이트웨이로 요청 실행
      // skipAuthRetry=true면 refreshToken을 넘기지 않아 401 시 갱신 안 함
      const { response, newTokens, authFailed } = await authenticatedFetch(
        url,
        {
          ...options,
          headers: {
            ...headers,
            ...options?.headers,
          },
          cache: 'no-store',
        },
        options?.skipAuthRetry ? undefined : refreshToken,
        'ServerApiClient'
      );

      // 새 토큰 → 쿠키 저장
      if (newTokens) {
        await this.setNewTokenCookies(newTokens);
      }

      // 인증 실패 → 쿠키 삭제 + 리다이렉트
      if (authFailed && !options?.skipAuthRetry) {
        await this.clearTokenCookies();
        redirect('/login');
      }

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        throw {
          status: response.status,
          message: errorData.message || 'An error occurred',
          errors: errorData.errors || errorData.error?.details,
          code: errorData.code,
        };
      }

      if (response.status === 204) {
        return undefined as T;
      }

      // 방어적 JSON 파싱: PHP 백엔드가 JSON 뒤에 경고/에러 텍스트를 붙여 보내는 경우 대응
      const text = await response.text();
      try {
        return JSON.parse(text);
      } catch (parseError) {
        // JSON 뒤에 trailing garbage가 있는 경우 복구 시도
        const match = text.match(/^(\{[\s\S]*\}|\[[\s\S]*\])/);
        if (match) {
          console.warn('[ServerApiClient] Response contained trailing data, recovering:', text.slice(match[1].length, match[1].length + 100));
          return JSON.parse(match[1]);
        }
        throw parseError;
      }
    } catch (error) {
      if (isNextRedirectError(error)) throw error;
      throw error;
    }
  }

  /**
   * GET 요청
   */
  async get<T>(endpoint: string, options?: { params?: Record<string, string> }): Promise<T> {
    let url = endpoint;
    if (options?.params) {
      const searchParams = new URLSearchParams(options.params);
      url = `${endpoint}?${searchParams.toString()}`;
    }
    return this.request<T>(url, { method: 'GET' });
  }

  /**
   * POST 요청
   */
  async post<T>(endpoint: string, data?: unknown): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'POST',
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  /**
   * PUT 요청
   */
  async put<T>(endpoint: string, data?: unknown): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'PUT',
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  /**
   * PATCH 요청
   */
  async patch<T>(endpoint: string, data?: unknown): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'PATCH',
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  /**
   * DELETE 요청
   */
  async delete<T>(endpoint: string, options?: { data?: unknown }): Promise<T> {
    return this.request<T>(endpoint, {
      method: 'DELETE',
      body: options?.data ? JSON.stringify(options.data) : undefined,
    });
  }
}

// 서버 액션용 API 클라이언트 인스턴스
export const apiClient = new ServerApiClient();
