/**
 * 견적 관리 서버 액션
 *
 * API Endpoints:
 * - GET /api/v1/quotes - 목록 조회
 * - GET /api/v1/quotes/{id} - 상세 조회
 * - POST /api/v1/quotes - 등록
 * - PUT /api/v1/quotes/{id} - 수정
 * - DELETE /api/v1/quotes/{id} - 삭제
 * - DELETE /api/v1/quotes/bulk - 일괄 삭제
 * - POST /api/v1/quotes/{id}/finalize - 최종 확정
 * - POST /api/v1/quotes/{id}/cancel-finalize - 확정 취소
 * - POST /api/v1/quotes/{id}/convert - 수주 전환
 * - GET /api/v1/quotes/number/preview - 견적번호 미리보기
 * - POST /api/v1/quotes/{id}/pdf - PDF 생성
 * - POST /api/v1/quotes/{id}/send/email - 이메일 발송
 * - POST /api/v1/quotes/{id}/send/kakao - 카카오 발송
 */

'use server';


import { isNextRedirectError } from '@/lib/utils/redirect-error';
import { serverFetch } from '@/lib/api/fetch-wrapper';
import type {
  Quote,
  QuoteApiData,
  QuoteApiPaginatedResponse,
  QuoteListParams,
  QuoteStatus,
  ProductCategory,
} from './types';
import { transformApiToFrontend, transformFrontendToApi } from './types';

// ===== 페이지네이션 타입 =====
export interface PaginationMeta {
  currentPage: number;
  lastPage: number;
  perPage: number;
  total: number;
}

// ===== 견적 목록 조회 =====
export async function getQuotes(params?: QuoteListParams): Promise<{
  success: boolean;
  data: Quote[];
  pagination: PaginationMeta;
  error?: string;
  __authError?: boolean;
}> {
  try {
    const searchParams = new URLSearchParams();

    if (params?.page) searchParams.set('page', String(params.page));
    if (params?.perPage) searchParams.set('size', String(params.perPage));
    if (params?.search) searchParams.set('q', params.search);
    if (params?.status) searchParams.set('status', params.status);
    if (params?.productCategory) searchParams.set('product_category', params.productCategory);
    if (params?.clientId) searchParams.set('client_id', params.clientId);
    if (params?.dateFrom) searchParams.set('date_from', params.dateFrom);
    if (params?.dateTo) searchParams.set('date_to', params.dateTo);
    if (params?.sortBy) searchParams.set('sort_by', params.sortBy);
    if (params?.sortOrder) searchParams.set('sort_order', params.sortOrder);

    const queryString = searchParams.toString();
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes${queryString ? `?${queryString}` : ''}`;

    console.log('[QuoteActions] GET quotes:', url);

    const { response, error } = await serverFetch(url, {
      method: 'GET',
    });

    if (error) {
      return {
        success: false,
        data: [],
        pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 },
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        data: [],
        pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 },
        error: '견적 목록 조회에 실패했습니다.',
      };
    }

    if (!response.ok) {
      console.warn('[QuoteActions] GET quotes error:', response.status);
      return {
        success: false,
        data: [],
        pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 },
        error: `API 오류: ${response.status}`,
      };
    }

    const result = await response.json();

    if (!result.success) {
      return {
        success: false,
        data: [],
        pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 },
        error: result.message || '견적 목록 조회에 실패했습니다.',
      };
    }

    // API 응답 구조: { success, data: { data: [], current_page, last_page, per_page, total } }
    const paginatedData: QuoteApiPaginatedResponse = result.data || {
      data: [],
      current_page: 1,
      last_page: 1,
      per_page: 20,
      total: 0,
    };

    const quotes = (paginatedData.data || []).map(transformApiToFrontend);

    return {
      success: true,
      data: quotes,
      pagination: {
        currentPage: paginatedData.current_page,
        lastPage: paginatedData.last_page,
        perPage: paginatedData.per_page,
        total: paginatedData.total,
      },
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] getQuotes error:', error);
    return {
      success: false,
      data: [],
      pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 },
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적 상세 조회 =====
export async function getQuoteById(id: string): Promise<{
  success: boolean;
  data?: Quote;
  error?: string;
  __authError?: boolean;
}> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/${id}`;

    const { response, error } = await serverFetch(url, {
      method: 'GET',
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '견적 조회에 실패했습니다.',
      };
    }

    if (!response.ok) {
      console.error('[QuoteActions] GET quote error:', response.status);
      return {
        success: false,
        error: `API 오류: ${response.status}`,
      };
    }

    const result = await response.json();

    if (!result.success || !result.data) {
      return {
        success: false,
        error: result.message || '견적 조회에 실패했습니다.',
      };
    }

    // 디버깅: API 응답 구조 확인
    console.log('[QuoteActions] getQuoteById raw data:', JSON.stringify({
      client_name: result.data.client_name,
      client: result.data.client,
      calculation_inputs: result.data.calculation_inputs,
      items: result.data.items?.map((item: Record<string, unknown>) => ({
        id: item.id,
        item_name: item.item_name,
        calculated_quantity: item.calculated_quantity,
        base_quantity: item.base_quantity,
        unit_price: item.unit_price,
        total_price: item.total_price,
      })),
    }, null, 2));

    return {
      success: true,
      data: transformApiToFrontend(result.data),
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] getQuoteById error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적 등록 =====
// 주의: 호출자가 transformFormDataToApi 또는 transformFrontendToApi로 변환한 데이터를 전달해야 함
export async function createQuote(
  data: Record<string, unknown>
): Promise<{ success: boolean; data?: Quote; error?: string; __authError?: boolean }> {
  try {
    // 이미 변환된 API 형식 데이터를 그대로 사용
    const apiData = data;

    console.log('[QuoteActions] POST quote request:', apiData);

    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes`;

    const { response, error } = await serverFetch(url, {
      method: 'POST',
      body: JSON.stringify(apiData),
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '견적 등록에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] POST quote response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        error: result.message || '견적 등록에 실패했습니다.',
      };
    }

    return {
      success: true,
      data: transformApiToFrontend(result.data),
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] createQuote error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적 수정 =====
// 주의: 호출자가 transformFormDataToApi 또는 transformFrontendToApi로 변환한 데이터를 전달해야 함
export async function updateQuote(
  id: string,
  data: Record<string, unknown>
): Promise<{ success: boolean; data?: Quote; error?: string; __authError?: boolean }> {
  try {
    // 이미 변환된 API 형식 데이터를 그대로 사용
    const apiData = data;

    console.log('[QuoteActions] PUT quote request:', apiData);

    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/${id}`;

    const { response, error } = await serverFetch(url, {
      method: 'PUT',
      body: JSON.stringify(apiData),
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '견적 수정에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] PUT quote response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        error: result.message || '견적 수정에 실패했습니다.',
      };
    }

    return {
      success: true,
      data: transformApiToFrontend(result.data),
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] updateQuote error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적 삭제 =====
export async function deleteQuote(id: string): Promise<{ success: boolean; error?: string; __authError?: boolean }> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/${id}`;

    const { response, error } = await serverFetch(url, {
      method: 'DELETE',
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '견적 삭제에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] DELETE quote response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        error: result.message || '견적 삭제에 실패했습니다.',
      };
    }

    return { success: true };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] deleteQuote error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적 일괄 삭제 =====
export async function bulkDeleteQuotes(ids: string[]): Promise<{ success: boolean; error?: string; __authError?: boolean }> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/bulk`;

    const { response, error } = await serverFetch(url, {
      method: 'DELETE',
      body: JSON.stringify({ ids: ids.map(id => parseInt(id, 10)) }),
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '견적 일괄 삭제에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] BULK DELETE quotes response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        error: result.message || '견적 일괄 삭제에 실패했습니다.',
      };
    }

    return { success: true };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] bulkDeleteQuotes error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적 최종 확정 =====
export async function finalizeQuote(id: string): Promise<{
  success: boolean;
  data?: Quote;
  error?: string;
  __authError?: boolean;
}> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/${id}/finalize`;

    const { response, error } = await serverFetch(url, {
      method: 'POST',
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '견적 확정에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] POST finalize response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        error: result.message || '견적 확정에 실패했습니다.',
      };
    }

    return {
      success: true,
      data: transformApiToFrontend(result.data),
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] finalizeQuote error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적 확정 취소 =====
export async function cancelFinalizeQuote(id: string): Promise<{
  success: boolean;
  data?: Quote;
  error?: string;
  __authError?: boolean;
}> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/${id}/cancel-finalize`;

    const { response, error } = await serverFetch(url, {
      method: 'POST',
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '견적 확정 취소에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] POST cancel-finalize response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        error: result.message || '견적 확정 취소에 실패했습니다.',
      };
    }

    return {
      success: true,
      data: transformApiToFrontend(result.data),
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] cancelFinalizeQuote error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적 → 수주 전환 =====
export async function convertQuoteToOrder(id: string): Promise<{
  success: boolean;
  data?: Quote;
  orderId?: string;
  error?: string;
  __authError?: boolean;
}> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/${id}/convert`;

    const { response, error } = await serverFetch(url, {
      method: 'POST',
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '수주 전환에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] POST convert response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        error: result.message || '수주 전환에 실패했습니다.',
      };
    }

    return {
      success: true,
      data: result.data?.quote ? transformApiToFrontend(result.data.quote) : undefined,
      orderId: result.data?.order?.id ? String(result.data.order.id) : undefined,
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] convertQuoteToOrder error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적번호 미리보기 =====
export async function getQuoteNumberPreview(): Promise<{
  success: boolean;
  data?: string;
  error?: string;
  __authError?: boolean;
}> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/number/preview`;

    const { response, error } = await serverFetch(url, {
      method: 'GET',
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    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?.quote_number || result.data,
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] getQuoteNumberPreview error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== PDF 생성 =====
export async function generateQuotePdf(id: string): Promise<{
  success: boolean;
  data?: Blob;
  error?: string;
  __authError?: boolean;
}> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/${id}/pdf`;

    const { response, error } = await serverFetch(url, {
      method: 'POST',
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: 'PDF 생성에 실패했습니다.',
      };
    }

    if (!response.ok) {
      const result = await response.json().catch(() => ({}));
      return {
        success: false,
        error: result.message || 'PDF 생성에 실패했습니다.',
      };
    }

    const blob = await response.blob();
    return {
      success: true,
      data: blob,
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] generateQuotePdf error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 이메일 발송 =====
export async function sendQuoteEmail(
  id: string,
  emailData: { email: string; subject?: string; message?: string }
): Promise<{ success: boolean; error?: string; __authError?: boolean }> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/${id}/send/email`;

    const { response, error } = await serverFetch(url, {
      method: 'POST',
      body: JSON.stringify(emailData),
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '이메일 발송에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] POST send email response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        error: result.message || '이메일 발송에 실패했습니다.',
      };
    }

    return { success: true };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] sendQuoteEmail error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 카카오 발송 =====
export async function sendQuoteKakao(
  id: string,
  kakaoData: { phone: string; templateId?: string }
): Promise<{ success: boolean; error?: string; __authError?: boolean }> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/${id}/send/kakao`;

    const { response, error } = await serverFetch(url, {
      method: 'POST',
      body: JSON.stringify(kakaoData),
    });

    if (error) {
      return {
        success: false,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        error: '카카오 발송에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] POST send kakao response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        error: result.message || '카카오 발송에 실패했습니다.',
      };
    }

    return { success: true };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] sendQuoteKakao error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 완제품(FG) 목록 조회 =====
export interface FinishedGoods {
  id: number;
  item_code: string;
  item_name: string;
  item_category: string;
  specification?: string;
  unit?: string;
  has_bom?: boolean;
  bom?: unknown[];
}

export async function getFinishedGoods(category?: string): Promise<{
  success: boolean;
  data: FinishedGoods[];
  error?: string;
  __authError?: boolean;
}> {
  try {
    const searchParams = new URLSearchParams();
    searchParams.set('item_type', 'FG');
    searchParams.set('has_bom', '1'); // BOM이 있는 제품만 조회
    if (category) {
      searchParams.set('item_category', category);
    }
    searchParams.set('size', '5000'); // 전체 조회 (테넌트별 FG 품목 수에 따라 조정)

    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/items?${searchParams.toString()}`;

    console.log('[QuoteActions] GET finished goods:', url);

    const { response, error } = await serverFetch(url, {
      method: 'GET',
    });

    if (error) {
      return {
        success: false,
        data: [],
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        data: [],
        error: '완제품 목록 조회에 실패했습니다.',
      };
    }

    if (!response.ok) {
      console.warn('[QuoteActions] GET finished goods error:', response.status);
      return {
        success: false,
        data: [],
        error: `API 오류: ${response.status}`,
      };
    }

    const result = await response.json();

    if (!result.success) {
      return {
        success: false,
        data: [],
        error: result.message || '완제품 목록 조회에 실패했습니다.',
      };
    }

    // API 응답: { success, data: { data: [], ... } } 또는 { success, data: [] }
    const items = result.data?.data || result.data || [];

    return {
      success: true,
      data: items.map((item: Record<string, unknown>) => ({
        id: item.id,
        item_code: (item.item_code || item.code) as string,  // API가 code → item_code로 변환
        item_name: item.name as string,
        item_category: (item.item_category as string) || '',
        specification: item.specification as string | undefined,
        unit: item.unit as string | undefined,
        has_bom: item.has_bom as boolean | undefined,
        bom: item.bom as unknown[] | undefined,
      })),
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] getFinishedGoods error:', error);
    return {
      success: false,
      data: [],
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== BOM 기반 자동 견적 산출 (다건) =====
export interface BomCalculateItem {
  finished_goods_code: string;
  // React 필드명 (camelCase) - API가 내부에서 W0/H0 등으로 변환
  openWidth: number;
  openHeight: number;
  quantity?: number;
  guideRailType?: string;
  motorPower?: string;
  controller?: string;
  wingSize?: number;
  inspectionFee?: number;
}

export interface BomCalculationResult {
  success?: boolean;
  finished_goods: {
    code: string;
    name: string;
    item_category?: string;
  };
  variables?: Record<string, unknown>;
  items: Array<{
    item_code: string;
    item_name: string;
    item_category?: string;
    specification?: string;
    unit?: string;
    quantity: number;
    quantity_formula?: string;
    base_price?: number;
    multiplier?: number;
    unit_price: number;
    total_price: number;
    calculation_note?: string;
    category_group?: string;
    process_group?: string;
    process_group_key?: string;
  }>;
  grouped_items?: Record<string, {
    name: string;
    items: Array<unknown>;
    subtotal: number;
  }>;
  subtotals: Record<string, { name?: string; count?: number; subtotal?: number; items?: unknown[] } | number>;
  grand_total: number;
  variables?: Record<string, unknown>;  // 계산된 변수들
  debug_steps?: Array<{ step: number; name: string; data: Record<string, unknown> }>;  // 10단계 계산 과정
}

// API 서버 응답 구조 (QuoteCalculationService::calculateBomBulk)
export interface BomBulkResponse {
  success: boolean;
  summary: {
    total_count: number;
    success_count: number;
    fail_count: number;
    grand_total: number;
  };
  items: Array<{
    index: number;
    finished_goods_code: string;
    inputs: Record<string, unknown>;
    result: BomCalculationResult;
  }>;
}

export async function calculateBomBulk(items: BomCalculateItem[], debug: boolean = true): Promise<{
  success: boolean;
  data: BomBulkResponse | null;
  error?: string;
  __authError?: boolean;
}> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/calculate/bom/bulk`;

    console.log('[QuoteActions] POST calculate BOM bulk:', { items, debug });

    const { response, error } = await serverFetch(url, {
      method: 'POST',
      body: JSON.stringify({ items, debug }),
    });

    if (error) {
      return {
        success: false,
        data: null,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        data: null,
        error: 'BOM 계산에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] POST calculate BOM bulk response:', result);

    if (!response.ok || !result.success) {
      // 검증 에러의 상세 메시지 추출
      let errorMessage = result.message || 'BOM 계산에 실패했습니다.';

      // error.details에 상세 검증 에러가 있는 경우
      if (result.error?.details && typeof result.error.details === 'object') {
        const detailMessages = Object.values(result.error.details)
          .flat()
          .filter((msg): msg is string => typeof msg === 'string');
        if (detailMessages.length > 0) {
          errorMessage = detailMessages.join(', ');
        }
      }

      return {
        success: false,
        data: null,
        error: errorMessage,
      };
    }

    return {
      success: true,
      data: result.data || null,
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] calculateBomBulk error:', error);
    return {
      success: false,
      data: null,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 품목 단가 조회 =====
export interface ItemPriceResult {
  item_code: string;
  unit_price: number;
}

export async function getItemPrices(itemCodes: string[]): Promise<{
  success: boolean;
  data: Record<string, ItemPriceResult> | null;
  error?: string;
  __authError?: boolean;
}> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/quotes/items/prices`;

    console.log('[QuoteActions] POST getItemPrices:', { itemCodes });

    const { response, error } = await serverFetch(url, {
      method: 'POST',
      body: JSON.stringify({ item_codes: itemCodes }),
    });

    if (error) {
      return {
        success: false,
        data: null,
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response) {
      return {
        success: false,
        data: null,
        error: '단가 조회에 실패했습니다.',
      };
    }

    const result = await response.json();
    console.log('[QuoteActions] POST getItemPrices response:', result);

    if (!response.ok || !result.success) {
      return {
        success: false,
        data: null,
        error: result.message || '단가 조회에 실패했습니다.',
      };
    }

    return {
      success: true,
      data: result.data || null,
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] getItemPrices error:', error);
    return {
      success: false,
      data: null,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 견적 요약 통계 =====
export async function getQuotesSummary(params?: {
  dateFrom?: string;
  dateTo?: string;
}): Promise<{
  success: boolean;
  data?: {
    totalAmount: number;
    totalCount: number;
    draftCount: number;
    draftAmount: number;
    finalizedCount: number;
    finalizedAmount: number;
    convertedCount: number;
    convertedAmount: number;
    conversionRate: number;
  };
  error?: string;
  __authError?: boolean;
}> {
  try {
    // 목록 조회를 통해 통계 계산 (별도 API 없는 경우)
    const listResult = await getQuotes({
      perPage: 1000, // 충분히 큰 수
      dateFrom: params?.dateFrom,
      dateTo: params?.dateTo,
    });

    if (!listResult.success) {
      return {
        success: false,
        error: listResult.error,
        __authError: listResult.__authError,
      };
    }

    const quotes = listResult.data;

    const draftQuotes = quotes.filter(q => q.status === 'draft');
    const finalizedQuotes = quotes.filter(q => q.isFinal);
    const convertedQuotes = quotes.filter(q => q.status === 'converted');

    const totalAmount = quotes.reduce((sum, q) => sum + q.totalAmount, 0);
    const draftAmount = draftQuotes.reduce((sum, q) => sum + q.totalAmount, 0);
    const finalizedAmount = finalizedQuotes.reduce((sum, q) => sum + q.totalAmount, 0);
    const convertedAmount = convertedQuotes.reduce((sum, q) => sum + q.totalAmount, 0);

    const conversionRate = quotes.length > 0
      ? (convertedQuotes.length / quotes.length) * 100
      : 0;

    return {
      success: true,
      data: {
        totalAmount,
        totalCount: quotes.length,
        draftCount: draftQuotes.length,
        draftAmount,
        finalizedCount: finalizedQuotes.length,
        finalizedAmount,
        convertedCount: convertedQuotes.length,
        convertedAmount,
        conversionRate,
      },
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] getQuotesSummary error:', error);
    return {
      success: false,
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 현장명 목록 조회 (자동완성용) =====
export async function getSiteNames(): Promise<{
  success: boolean;
  data: string[];
  error?: string;
  __authError?: boolean;
}> {
  try {
    // 기존 견적에서 현장명 수집 (중복 제거)
    const listResult = await getQuotes({
      perPage: 500,
    });

    if (!listResult.success) {
      return {
        success: false,
        data: [],
        error: listResult.error,
        __authError: listResult.__authError,
      };
    }

    // 현장명 추출 및 중복 제거
    const siteNames = Array.from(
      new Set(
        listResult.data
          .map(q => q.siteName)
          .filter((name): name is string => !!name && name.trim() !== '')
      )
    ).sort();

    return {
      success: true,
      data: siteNames,
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] getSiteNames error:', error);
    return {
      success: false,
      data: [],
      error: '서버 오류가 발생했습니다.',
    };
  }
}

// ===== 품목 카테고리 트리 조회 =====
export interface ItemCategoryNode {
  id: number;
  code: string;
  name: string;
  is_active: number;
  sort_order: number;
  children: ItemCategoryNode[];
}

export async function getItemCategoryTree(): Promise<{
  success: boolean;
  data: ItemCategoryNode[];
  error?: string;
  __authError?: boolean;
}> {
  try {
    const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/categories/tree?code_group=item_category&only_active=true`;
    const { response, error } = await serverFetch(url, { method: 'GET' });

    if (error) {
      return {
        success: false,
        data: [],
        error: error.message,
        __authError: error.code === 'UNAUTHORIZED',
      };
    }

    if (!response || !response.ok) {
      console.error('[getItemCategoryTree] response status:', response?.status, response?.statusText);
      const errorBody = response ? await response.text().catch(() => '') : '';
      console.error('[getItemCategoryTree] response body:', errorBody);
      return { success: false, data: [], error: `카테고리 조회 실패 (${response?.status || 'no response'})` };
    }

    const result = await response.json();
    return {
      success: true,
      data: result.data || [],
    };
  } catch (error) {
    if (isNextRedirectError(error)) throw error;
    console.error('[QuoteActions] getItemCategoryTree error:', error);
    return {
      success: false,
      data: [],
      error: '서버 오류가 발생했습니다.',
    };
  }
}