/**
 * 견적 관리 타입 정의
 *
 * API 모델: Quote.php
 * - status: draft, sent, approved, rejected, finalized, converted
 * - product_category: screen, steel
 */

import { formatDateForInput } from "@/lib/utils/date";

// ===== 견적 상태 =====
export type QuoteStatus =
  | 'draft'      // 작성중
  | 'sent'       // 발송완료
  | 'approved'   // 승인
  | 'rejected'   // 거절
  | 'finalized'  // 최종확정
  | 'converted'; // 수주전환

export const QUOTE_STATUS_LABELS: Record<QuoteStatus, string> = {
  draft: '작성중',
  sent: '발송완료',
  approved: '승인',
  rejected: '거절',
  finalized: '견적완료',
  converted: '수주전환',
};

export const QUOTE_STATUS_COLORS: Record<QuoteStatus, string> = {
  draft: 'bg-gray-100 text-gray-800',
  sent: 'bg-blue-100 text-blue-800',
  approved: 'bg-green-100 text-green-800',
  rejected: 'bg-red-100 text-red-800',
  finalized: 'bg-purple-100 text-purple-800',
  converted: 'bg-indigo-100 text-indigo-800',
};

// ===== 제품 카테고리 =====
export type ProductCategory = 'SCREEN' | 'STEEL';

export const PRODUCT_CATEGORY_LABELS: Record<string, string> = {
  SCREEN: '스크린',
  STEEL: '철재',
  screen: '스크린',
  steel: '철재',
};

// ===== BOM 카테고리 순서 (고정) =====
// 주자재 → 모터 → 제어기 → 절곡품 → 부자재 → 검사비 → 기타
export const BOM_CATEGORY_ORDER = ['material', 'motor', 'controller', 'steel', 'parts', 'inspection'];

export const BOM_CATEGORY_LABELS: Record<string, string> = {
  material: '주자재',
  motor: '모터',
  controller: '제어기',
  steel: '절곡품',
  parts: '부자재',
  inspection: '검사비',
};

/** item_category(한글) → product_category 변환 (DB는 대문자) */
export function itemCategoryToProductCategory(itemCategory?: string): ProductCategory {
  if (itemCategory === '철재') return 'STEEL';
  return 'SCREEN';
}

/** 개소 목록에서 견적 전체의 product_category 결정 */
function deriveProductCategory(locations: LocationItem[]): ProductCategory {
  const categories = new Set(locations.map(loc => itemCategoryToProductCategory(loc.itemCategory)));
  if (categories.size === 1) return categories.values().next().value!;
  return itemCategoryToProductCategory(locations[0]?.itemCategory);
}

// ===== 견적 품목 =====
export interface QuoteItem {
  id: string;
  quoteId: string;
  productId?: string;
  itemCode?: string;  // 품목코드 (item_code)
  productName: string;
  specification?: string;
  unit?: string;
  quantity: number;
  unitPrice: number;
  supplyAmount: number;
  taxAmount: number;
  totalAmount: number;
  sortOrder: number;
  note?: string;
}

// ===== 견적 레코드 (프론트엔드 타입) =====
export interface Quote {
  id: string;
  quoteNumber: string;
  registrationDate: string;
  clientId: string;
  clientName: string;
  siteName?: string;
  siteCode?: string;
  managerName?: string;
  managerContact?: string;
  productCategory: ProductCategory;
  quantity: number;
  unitSymbol?: string;  // 단위 (개소, set 등)
  supplyAmount: number;
  taxAmount: number;
  totalAmount: number;
  discountRate: number;
  discountAmount: number;
  status: QuoteStatus;
  currentRevision: number;
  isFinal: boolean;
  description?: string;
  validUntil?: string;
  deliveryDate?: string;
  deliveryLocation?: string;
  paymentTerms?: string;
  items: QuoteItem[];
  calculationInputs?: CalculationInputs;  // 자동산출 입력값 (폼 복원용)
  bomMaterials?: BomMaterial[];  // BOM 자재 목록
  createdAt: string;
  updatedAt: string;
  createdBy?: string;
  updatedBy?: string;
  finalizedAt?: string;
  finalizedBy?: string;
  orderId?: number | null;  // 연결된 수주 ID (수주전환 시 설정)
}

// ===== API 응답 타입 =====
// 자동산출 입력값 타입
export interface CalculationInputItem {
  productCategory?: string;
  itemCategory?: string;    // 품목 카테고리 원본 (스크린/철재) - round-trip용
  productCode?: string;     // 제품코드
  productName?: string;
  openWidth?: string;
  openHeight?: string;
  guideRailType?: string;
  motorPower?: string;
  controller?: string;
  wingSize?: string;
  inspectionFee?: number;
  floor?: string;
  code?: string;
  quantity?: number;  // 수량
}

export interface CalculationInputs {
  items?: CalculationInputItem[];
  bomResults?: BomCalculationResult[];  // BOM 산출 결과 (수동 추가 품목 포함)
}

// BOM 자재 항목 타입 (API 응답)
export interface BomMaterialApiData {
  item_index: number;
  finished_goods_code: string;
  item_code: string;
  item_name: string;
  item_type: string;       // 품목 유형 (RM: 원자재, SM: 부자재, CS: 소모품)
  item_category: string;   // 품목 카테고리
  specification: string;
  unit: string;
  quantity: number;
  unit_price: number;
  total_price: number;
  process_type: string;    // 공정 유형
}

export interface QuoteApiData {
  id: number;
  quote_number: string;
  registration_date: string;
  client_id: number | null;
  client_name: string;
  client?: {
    id: number;
    name: string;
  };
  site_name: string | null;
  site_code: string | null;
  // 담당자/연락처 - API 실제 필드명과 레거시 호환
  manager?: string | null;           // API 실제 필드명
  contact?: string | null;           // API 실제 필드명
  manager_name?: string | null;      // 레거시 호환
  manager_contact?: string | null;   // 레거시 호환
  product_category: 'screen' | 'steel';
  quantity: number;
  unit_symbol?: string | null;  // 단위 (개소, set 등)
  supply_amount: string | number;
  tax_amount: string | number;
  total_amount: string | number;
  discount_rate?: number | null;     // 할인율 (%)
  discount_amount?: number | null;   // 할인 금액
  status: QuoteStatus;
  current_revision: number;
  is_final: boolean;
  // 비고/납기일 - API 실제 필드명과 레거시 호환
  remarks?: string | null;           // API 실제 필드명
  completion_date?: string | null;   // API 실제 필드명
  description?: string | null;       // 레거시 호환
  valid_until?: string | null;
  delivery_date?: string | null;     // 레거시 호환
  delivery_location?: string | null;
  payment_terms?: string | null;
  calculation_inputs?: CalculationInputs | null;
  items?: QuoteItemApiData[];
  bom_materials?: BomMaterialApiData[];  // BOM 자재 목록
  created_at: string;
  updated_at: string;
  created_by: number | null;
  updated_by: number | null;
  finalized_at: string | null;
  finalized_by: number | null;
  // options JSON (부가세 타입 등)
  options?: Record<string, unknown> | null;
  // 연결된 수주 ID (수주전환 시 설정)
  order_id?: number | null;
  // 관계 데이터 (with 로드 시)
  creator?: {
    id: number;
    name: string;
  } | null;
  updater?: {
    id: number;
    name: string;
  } | null;
  finalizer?: {
    id: number;
    name: string;
  } | null;
}

export interface QuoteItemApiData {
  id: number;
  quote_id: number;
  // 품목 정보 (API는 item_name/item_code 사용)
  item_id?: number | null;
  item_code?: string | null;
  item_name: string;
  product_id?: number | null;  // 레거시 호환
  product_name?: string;       // 레거시 호환
  specification: string | null;
  unit: string | null;
  // 수량/금액 (API는 calculated_quantity, total_price 사용)
  base_quantity?: number;
  calculated_quantity?: number;
  quantity?: number;  // 레거시 호환
  unit_price: string | number;
  total_price?: string | number;
  supply_amount?: string | number;  // 레거시 호환
  tax_amount?: string | number;     // 레거시 호환
  total_amount?: string | number;   // 레거시 호환
  sort_order: number;
  note: string | null;
}

// ===== API 페이지네이션 응답 =====
export interface QuoteApiPaginatedResponse {
  data: QuoteApiData[];
  current_page: number;
  last_page: number;
  per_page: number;
  total: number;
}

// ===== 변환 함수: API → 프론트엔드 =====
export function transformApiToFrontend(apiData: QuoteApiData): Quote {
  return {
    id: String(apiData.id),
    quoteNumber: apiData.quote_number,
    registrationDate: apiData.registration_date,
    clientId: apiData.client_id ? String(apiData.client_id) : '',
    clientName: apiData.client?.name || apiData.client_name || '',
    siteName: apiData.site_name || undefined,
    siteCode: apiData.site_code || undefined,
    // API 실제 필드명(manager, contact) 우선, 레거시 필드명(manager_name, manager_contact) 폴백
    managerName: apiData.manager || apiData.manager_name || undefined,
    managerContact: apiData.contact || apiData.manager_contact || undefined,
    productCategory: (apiData.product_category?.toUpperCase() || 'SCREEN') as ProductCategory,
    quantity: apiData.quantity || 0,
    unitSymbol: apiData.unit_symbol || undefined,
    supplyAmount: parseFloat(String(apiData.supply_amount)) || 0,
    taxAmount: parseFloat(String(apiData.tax_amount)) || 0,
    totalAmount: parseFloat(String(apiData.total_amount)) || 0,
    discountRate: Number(apiData.discount_rate) || 0,
    discountAmount: Number(apiData.discount_amount) || 0,
    status: apiData.status,
    currentRevision: apiData.current_revision || 0,
    isFinal: apiData.is_final || false,
    // API 실제 필드명(remarks, completion_date) 우선, 레거시 필드명(description, delivery_date) 폴백
    description: apiData.remarks || apiData.description || undefined,
    validUntil: apiData.valid_until || undefined,
    deliveryDate: apiData.completion_date || apiData.delivery_date || undefined,
    deliveryLocation: apiData.delivery_location || undefined,
    paymentTerms: apiData.payment_terms || undefined,
    items: (apiData.items || []).map(transformItemApiToFrontend),
    calculationInputs: apiData.calculation_inputs || undefined,  // 자동산출 입력값 포함
    bomMaterials: (apiData.bom_materials || []).map(transformBomMaterialApiToFrontend),  // BOM 자재 목록
    createdAt: apiData.created_at,
    updatedAt: apiData.updated_at,
    createdBy: apiData.creator?.name || undefined,
    updatedBy: apiData.updater?.name || undefined,
    finalizedAt: apiData.finalized_at || undefined,
    finalizedBy: apiData.finalizer?.name || undefined,
    orderId: apiData.order_id ?? undefined,  // 연결된 수주 ID
  };
}

export function transformItemApiToFrontend(apiData: QuoteItemApiData): QuoteItem {
  // API 필드 우선순위: item_name > product_name
  const productName = apiData.item_name || apiData.product_name || '';
  // API 필드 우선순위: calculated_quantity > quantity > base_quantity (정수로 변환)
  const rawQuantity = apiData.calculated_quantity ?? apiData.quantity ?? apiData.base_quantity ?? 0;
  const quantity = Math.round(rawQuantity);
  // API 필드 우선순위: total_price > total_amount > supply_amount
  const totalAmount = parseFloat(String(apiData.total_price ?? apiData.total_amount ?? apiData.supply_amount ?? 0)) || 0;

  return {
    id: String(apiData.id),
    quoteId: String(apiData.quote_id),
    productId: apiData.item_id ? String(apiData.item_id) : (apiData.product_id ? String(apiData.product_id) : undefined),
    itemCode: apiData.item_code || undefined,  // 품목코드
    productName,
    specification: apiData.specification || undefined,
    unit: apiData.unit || undefined,
    quantity,
    unitPrice: parseFloat(String(apiData.unit_price)) || 0,
    supplyAmount: totalAmount,  // total_price를 supplyAmount로 사용
    taxAmount: parseFloat(String(apiData.tax_amount)) || 0,
    totalAmount,
    sortOrder: apiData.sort_order || 0,
    note: apiData.note || undefined,
  };
}

// ===== 변환 함수: 프론트엔드 → API =====
export function transformFrontendToApi(data: Partial<Quote>): Record<string, unknown> {
  const apiData: Record<string, unknown> = {};

  if (data.registrationDate !== undefined) apiData.registration_date = data.registrationDate;
  if (data.clientId !== undefined) apiData.client_id = data.clientId ? parseInt(data.clientId, 10) : null;
  if (data.clientName !== undefined) apiData.client_name = data.clientName;
  if (data.siteName !== undefined) apiData.site_name = data.siteName || null;
  if (data.siteCode !== undefined) apiData.site_code = data.siteCode || null;
  if (data.managerName !== undefined) apiData.manager_name = data.managerName || null;
  if (data.managerContact !== undefined) apiData.manager_contact = data.managerContact || null;
  if (data.productCategory !== undefined) apiData.product_category = data.productCategory;
  if (data.quantity !== undefined) apiData.quantity = data.quantity;
  if (data.supplyAmount !== undefined) apiData.supply_amount = data.supplyAmount;
  if (data.taxAmount !== undefined) apiData.tax_amount = data.taxAmount;
  if (data.totalAmount !== undefined) apiData.total_amount = data.totalAmount;
  if (data.description !== undefined) apiData.description = data.description || null;
  if (data.validUntil !== undefined) apiData.valid_until = data.validUntil || null;
  if (data.deliveryDate !== undefined) apiData.delivery_date = data.deliveryDate || null;
  if (data.deliveryLocation !== undefined) apiData.delivery_location = data.deliveryLocation || null;
  if (data.paymentTerms !== undefined) apiData.payment_terms = data.paymentTerms || null;

  // 품목 변환
  if (data.items !== undefined) {
    apiData.items = data.items.map(item => ({
      product_id: item.productId ? parseInt(item.productId, 10) : null,
      product_name: item.productName,
      specification: item.specification || null,
      unit: item.unit || null,
      quantity: item.quantity,
      unit_price: item.unitPrice,
      supply_amount: item.supplyAmount,
      tax_amount: item.taxAmount,
      total_amount: item.totalAmount,
      sort_order: item.sortOrder,
      note: item.note || null,
    }));
  }

  return apiData;
}

// ===== 탭 필터 옵션 =====
export type QuoteFilterType = 'all' | 'initial' | 'revising' | 'final' | 'converted';

export const QUOTE_FILTER_OPTIONS: { value: QuoteFilterType; label: string }[] = [
  { value: 'all', label: '전체' },
  { value: 'initial', label: '최초작성' },
  { value: 'revising', label: '수정중' },
  { value: 'final', label: '견적완료' },
  { value: 'converted', label: '수주전환' },
];

// ===== 목록 조회 파라미터 =====
export interface QuoteListParams {
  page?: number;
  perPage?: number;
  search?: string;
  status?: QuoteStatus;
  productCategory?: ProductCategory;
  clientId?: string;
  dateFrom?: string;
  dateTo?: string;
  sortBy?: string;
  sortOrder?: 'asc' | 'desc';
}

// ===== QuoteFormData 호환용 타입 (QuoteRegistration 컴포넌트용) =====
export interface QuoteFormItem {
  id: string;
  floor: string;
  code: string;
  productCategory: string;
  productName: string;
  openWidth: string;
  openHeight: string;
  guideRailType: string;
  motorPower: string;
  controller: string;
  quantity: number;
  unit?: string;  // 품목 단위
  wingSize: string;
  inspectionFee: number;
  unitPrice?: number;
  totalAmount?: number;
  installType?: string;
}

// BOM 자재 항목 (프론트엔드용)
export interface BomMaterial {
  itemIndex: number;
  finishedGoodsCode: string;
  itemCode: string;
  itemName: string;
  itemType: string;       // 품목 유형 (RM: 원자재, SM: 부자재, CS: 소모품)
  itemCategory: string;   // 품목 카테고리
  specification: string;
  unit: string;
  quantity: number;
  unitPrice: number;
  totalPrice: number;
  processType: string;    // 공정 유형
}

// BOM 계산 결과 아이템 타입
export interface BomCalculationResultItem {
  item_id?: number | null;
  item_code: string;
  item_name: string;
  item_category?: string;      // 품목 카테고리
  specification?: string;
  unit?: string;
  quantity: number;            // 1개당 BOM 수량 (base_quantity)
  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;  // Legacy 공정 그룹 키
  category_code?: string;      // 아이템 카테고리 코드 (동적 카테고리 시스템)
  is_manual?: boolean;         // 수동 추가 품목 여부
}

// BOM 계산 디버그 스텝 타입
export interface BomDebugStep {
  step: number;
  name: string;
  data: Record<string, unknown>;
}

// BOM 계산 결과 타입
export interface BomCalculationResult {
  success?: boolean;  // API 응답 시 성공 여부
  finished_goods: {
    code: string;
    name: string;
    item_category?: string;
  };
  items: BomCalculationResultItem[];
  subtotals: Record<string, { name?: string; count?: number; subtotal?: number } | number>;
  grouped_items?: Record<string, { items: BomCalculationResultItem[]; [key: string]: unknown }>;
  grand_total: number;
  variables?: Record<string, unknown>;  // 계산된 변수들
  debug_steps?: BomDebugStep[];  // 디버그 스텝 (개발용)
}

// 견적 산출 결과 타입
export interface CalculationResults {
  summary: { grand_total: number };
  items: Array<{
    index: number;
    result: BomCalculationResult;
  }>;
}

export interface QuoteFormData {
  id?: string;
  registrationDate: string;
  writer: string;
  clientId: string;
  clientName: string;
  siteName: string;
  manager: string;
  contact: string;
  dueDate: string;
  remarks: string;
  unitSymbol?: string;  // 선택한 제품(모델)의 단위 (개소, set 등)
  items: QuoteFormItem[];
  bomMaterials?: BomMaterial[];  // BOM 자재 목록
  calculationResults?: CalculationResults;  // 견적 산출 결과 (저장 시 BOM 자재 변환용)
}

// ===== Quote → QuoteFormData 변환 =====
export function transformQuoteToFormData(quote: Quote): QuoteFormData {
  const calcInputs = quote.calculationInputs?.items || [];

  // BOM 자재(quote.items)의 총 금액 계산
  const totalBomAmount = quote.items.reduce((sum, item) => sum + (item.totalAmount || 0), 0);
  const itemCount = calcInputs.length || 1;
  const amountPerItem = Math.round(totalBomAmount / itemCount);

  // 디버깅 로그

  return {
    id: quote.id,
    registrationDate: formatDateForInput(quote.registrationDate),
    writer: quote.createdBy || '',
    clientId: quote.clientId,
    clientName: quote.clientName,
    siteName: quote.siteName || '',
    manager: quote.managerName || '',
    contact: quote.managerContact || '',
    dueDate: formatDateForInput(quote.deliveryDate),
    remarks: quote.description || '',
    unitSymbol: quote.unitSymbol,  // 단위 (EA, 개소 등)
    // calculation_inputs.items가 있으면 그것으로 items 복원 (견적 탭 = 사용자가 입력한 수)
    // 없으면 quote.items 사용 (레거시 호환)
    items: calcInputs.length > 0
      ? calcInputs.map((calcInput, index) => ({
          id: `temp-${index}`,  // 임시 ID (새로 저장 시 갱신됨)
          floor: calcInput.floor || '',
          code: calcInput.code || '',
          productCategory: calcInput.productCategory || '',
          productName: calcInput.productName || '',
          openWidth: calcInput.openWidth || '',
          openHeight: calcInput.openHeight || '',
          guideRailType: calcInput.guideRailType || '',
          motorPower: calcInput.motorPower || '',
          controller: calcInput.controller || '',
          quantity: calcInput.quantity || 1,
          unit: undefined,  // BOM 자재에서 가져올 수 있지만 입력 시점에는 없음
          wingSize: calcInput.wingSize || '50',
          inspectionFee: calcInput.inspectionFee || 50000,
          // 금액은 BOM 자재 총합을 탭 수로 나눠서 배분
          unitPrice: Math.round(amountPerItem / (calcInput.quantity || 1)),
          totalAmount: amountPerItem,
        }))
      : quote.items.map((item, _index) => {
          const spec = item.specification || '';
          // specification에서 width x height 추출 (예: "3000x2500mm")
          const sizeMatch = spec.match(/(\d+)\s*x\s*(\d+)/i);

          return {
            id: item.id,
            floor: '',
            code: '',
            productCategory: '',
            productName: item.productName,
            openWidth: sizeMatch ? sizeMatch[1] : '',
            openHeight: sizeMatch ? sizeMatch[2] : '',
            guideRailType: '',
            motorPower: '',
            controller: '',
            quantity: item.quantity || 1,
            unit: item.unit,
            wingSize: '50',
            inspectionFee: item.unitPrice || 50000,
            unitPrice: item.unitPrice,
            totalAmount: item.totalAmount,
          };
        }),
    // BOM 자재 목록:
    // - API에서 bom_materials를 계산하여 반환 (item_type 포함)
    // - quote.bomMaterials가 있으면 그대로 사용
    bomMaterials: quote.bomMaterials,
  };
}

// ===== BOM 자재 변환 함수 =====
export function transformBomMaterialApiToFrontend(apiData: BomMaterialApiData): BomMaterial {
  return {
    itemIndex: apiData.item_index,
    finishedGoodsCode: apiData.finished_goods_code,
    itemCode: apiData.item_code,
    itemName: apiData.item_name,
    itemType: apiData.item_type,           // 품목 유형 (RM, SM, CS)
    itemCategory: apiData.item_category,   // 품목 카테고리
    specification: apiData.specification,
    unit: apiData.unit,
    quantity: apiData.quantity,
    unitPrice: apiData.unit_price,
    totalPrice: apiData.total_price,
    processType: apiData.process_type,     // 공정 유형
  };
}

// ===== QuoteApiData → QuoteFormData 변환 (calculation_inputs + bom_materials 포함) =====
export function transformApiDataToFormData(apiData: QuoteApiData): QuoteFormData {
  const calcInputs = apiData.calculation_inputs?.items || [];

  // BOM 자재(apiData.items)의 총 금액 계산
  const totalBomAmount = (apiData.items || []).reduce((sum, item) => {
    const itemTotal = parseFloat(String(item.total_price ?? item.total_amount ?? 0)) || 0;
    return sum + itemTotal;
  }, 0);
  const itemCount = calcInputs.length || 1;
  const amountPerItem = Math.round(totalBomAmount / itemCount);


  return {
    id: String(apiData.id),
    registrationDate: formatDateForInput(apiData.registration_date),
    writer: apiData.creator?.name || '',
    clientId: apiData.client_id ? String(apiData.client_id) : '',
    clientName: apiData.client?.name || apiData.client_name || '',
    siteName: apiData.site_name || '',
    // API 실제 필드명(manager, contact) 우선, 레거시 필드명(manager_name, manager_contact) 폴백
    manager: apiData.manager || apiData.manager_name || '',
    contact: apiData.contact || apiData.manager_contact || '',
    // API 실제 필드명(completion_date, remarks) 우선, 레거시 필드명(delivery_date, description) 폴백
    // 날짜는 YYYY-MM-DD 형식으로 변환
    dueDate: formatDateForInput(apiData.completion_date || apiData.delivery_date),
    remarks: apiData.remarks || apiData.description || '',
    unitSymbol: apiData.unit_symbol || undefined,  // 단위 (EA, 개소 등)
    // calculation_inputs.items가 있으면 그것으로 items 복원 (견적 탭 = 사용자가 입력한 수)
    // 없으면 apiData.items 사용 (레거시 호환)
    items: calcInputs.length > 0
      ? calcInputs.map((calcInput, index) => ({
          id: `temp-${index}`,  // 임시 ID (새로 저장 시 갱신됨)
          floor: calcInput.floor || '',
          code: calcInput.code || '',
          productCategory: calcInput.productCategory || '',
          productName: calcInput.productName || '',
          openWidth: calcInput.openWidth || '',
          openHeight: calcInput.openHeight || '',
          guideRailType: calcInput.guideRailType || '',
          motorPower: calcInput.motorPower || '',
          controller: calcInput.controller || '',
          quantity: calcInput.quantity || 1,
          unit: undefined,  // BOM 자재에서 가져올 수 있지만 입력 시점에는 없음
          wingSize: calcInput.wingSize || '50',
          inspectionFee: calcInput.inspectionFee || 50000,
          // 금액은 BOM 자재 총합을 탭 수로 나눠서 배분
          unitPrice: Math.round(amountPerItem / (calcInput.quantity || 1)),
          totalAmount: amountPerItem,
        }))
      : (apiData.items || []).map((item, _index) => {
          const spec = item.specification || '';
          // specification에서 width x height 추출 (예: "3000x2500mm")
          const sizeMatch = spec.match(/(\d+)\s*x\s*(\d+)/i);
          // 수량: calculated_quantity > base_quantity > quantity 순으로 확인
          const itemQuantity = item.calculated_quantity ?? item.base_quantity ?? item.quantity ?? 1;

          return {
            id: String(item.id),
            floor: '',
            code: '',
            productCategory: '',
            productName: item.product_name || '',
            openWidth: sizeMatch ? sizeMatch[1] : '',
            openHeight: sizeMatch ? sizeMatch[2] : '',
            guideRailType: '',
            motorPower: '',
            controller: '',
            quantity: Math.round(itemQuantity),
            unit: item.unit || undefined,
            wingSize: '50',
            inspectionFee: 50000,
            unitPrice: parseFloat(String(item.unit_price)) || 0,
            totalAmount: parseFloat(String(item.total_amount)) || 0,
          };
        }),
    // BOM 자재 목록 변환
    bomMaterials: (apiData.bom_materials || []).map(transformBomMaterialApiToFrontend),
  };
}

// =============================================================================
// V2 타입 정의 (QuoteRegistrationV2 컴포넌트용)
// =============================================================================

/**
 * 발주 개소 항목 (V2)
 * - 좌우 분할 레이아웃에서 사용되는 개소별 데이터 구조
 */
export interface LocationItem {
  id: string;
  floor: string;           // 층
  code: string;            // 부호
  openWidth: number;       // 가로 (오픈사이즈 W)
  openHeight: number;      // 세로 (오픈사이즈 H)
  productCode: string;     // 제품코드
  productName: string;     // 제품명
  itemCategory?: string;   // 품목 카테고리 (스크린/철재)
  quantity: number;        // 수량
  guideRailType: string;   // 가이드레일 설치 유형
  motorPower: string;      // 모터 전원
  controller: string;      // 연동제어기
  wingSize: number;        // 마구리 날개치수
  inspectionFee: number;   // 검사비
  // 계산 결과
  manufactureWidth?: number;   // 제작사이즈 W
  manufactureHeight?: number;  // 제작사이즈 H
  weight?: number;             // 산출중량 (kg)
  area?: number;               // 산출면적 (m²)
  unitPrice?: number;          // 단가
  totalPrice?: number;         // 합계
  bomResult?: BomCalculationResult;  // BOM 계산 결과
}

/**
 * 견적 폼 데이터 V2
 * - QuoteRegistrationV2 컴포넌트에서 사용하는 폼 데이터 구조
 * - V1의 QuoteFormData와 달리 locations[] 배열로 개소 관리
 */
export interface QuoteFormDataV2 {
  id?: string;
  quoteNumber?: string;  // 견적번호
  registrationDate: string;
  writer: string;
  clientId: string;
  clientName: string;
  siteName: string;
  manager: string;
  contact: string;
  dueDate: string;
  remarks: string;
  status: 'draft' | 'temporary' | 'final' | 'converted';  // 작성중, 임시저장, 최종저장, 수주전환

  vatType: 'included' | 'excluded';  // 부가세 포함/별도
  discountRate: number;     // 할인율 (%)
  discountAmount: number;   // 할인 금액
  locations: LocationItem[];
  orderId?: number | null;  // 연결된 수주 ID (수주전환 시 설정)
  isEditable?: boolean;     // 수정 가능 여부 (생산지시 존재 시 false)
  hasWorkOrders?: boolean;  // 연결된 수주에 생산지시 존재 여부
}

// =============================================================================
// V2 변환 함수
// =============================================================================

/**
 * V2 폼 데이터 → API 요청 형식 변환
 *
 * 핵심 차이점:
 * - V2는 locations[] 배열, API는 items[] + calculation_inputs.items[] 구조
 * - V2 status는 4가지 (draft/temporary/final/converted), API status는 6가지
 * - BOM 산출 결과가 있으면 items에 자재 상세 포함
 */
export function transformV2ToApi(
  data: QuoteFormDataV2,
  bomResults?: BomCalculationResult[]
): Record<string, unknown> {

  // 1. calculation_inputs 생성 (폼 복원용)
  // bomResults 수집 (인자로 받은 것 또는 locations에 저장된 것)
  const collectedBomResults = bomResults || data.locations
    .map(loc => loc.bomResult)
    .filter((br): br is BomCalculationResult => br !== undefined);

  const calculationInputs: CalculationInputs & { bomResults?: BomCalculationResult[] } = {
    items: data.locations.map(loc => ({
      productCategory: itemCategoryToProductCategory(loc.itemCategory),
      itemCategory: loc.itemCategory,  // round-trip용
      productCode: loc.productCode,  // BOM 재계산용
      productName: loc.productName,
      openWidth: String(loc.openWidth),
      openHeight: String(loc.openHeight),
      guideRailType: loc.guideRailType,
      motorPower: loc.motorPower,
      controller: loc.controller,
      wingSize: String(loc.wingSize),
      inspectionFee: loc.inspectionFee,
      floor: loc.floor,
      code: loc.code,
      quantity: loc.quantity,
    })),
    // BOM 결과 저장 (조회 시 복원용)
    bomResults: collectedBomResults.length > 0 ? collectedBomResults : undefined,
  };

  // 2. items 생성 (BOM 결과 있으면 자재 상세, 없으면 완제품 기준)
  let items: Array<{
    item_id?: number | null;
    item_name: string;
    item_code: string;
    specification: string | null;
    unit: string;
    quantity: number;
    base_quantity: number;
    calculated_quantity: number;
    unit_price: number;
    total_price: number;
    sort_order: number;
    note: string | null;
    formula_source?: string;
    item_index?: number;
    finished_goods_code?: string;
    formula_category?: string;
  }> = [];

  if (bomResults && bomResults.length > 0) {
    // BOM 자재 기반
    let sortOrder = 1;
    bomResults.forEach((bomResult, locIndex) => {
      const loc = data.locations[locIndex];
      const orderQty = loc?.quantity || 1;

      bomResult.items.forEach(bomItem => {
        const baseQty = bomItem.quantity;
        const calcQty = bomItem.unit === 'EA'
          ? Math.round(baseQty * orderQty)
          : parseFloat((baseQty * orderQty).toFixed(2));

        items.push({
          item_id: bomItem.item_id || null,
          item_name: bomItem.item_name,
          item_code: bomItem.item_code,
          specification: bomItem.specification || null,
          unit: bomItem.unit || 'EA',
          quantity: orderQty,
          base_quantity: baseQty,
          calculated_quantity: calcQty,
          unit_price: bomItem.unit_price,
          total_price: bomItem.unit_price * calcQty,
          sort_order: sortOrder++,
          note: [loc?.floor, loc?.code].filter(v => v && v !== '-').join(' ') || null,
          formula_source: `product_${locIndex}`,
          item_index: locIndex,
          finished_goods_code: bomResult.finished_goods.code,
          formula_category: bomItem.process_group || undefined,
        });
      });
    });
  } else if (data.locations.some(loc => loc.bomResult)) {
    // locations에 저장된 bomResult 사용
    let sortOrder = 1;
    data.locations.forEach((loc, locIndex) => {
      if (loc.bomResult) {
        const orderQty = loc.quantity || 1;
        loc.bomResult.items.forEach(bomItem => {
          const baseQty = bomItem.quantity;
          const calcQty = bomItem.unit === 'EA'
            ? Math.round(baseQty * orderQty)
            : parseFloat((baseQty * orderQty).toFixed(2));

          items.push({
            item_id: bomItem.item_id || null,
            item_name: bomItem.item_name,
            item_code: bomItem.item_code,
            specification: bomItem.specification || null,
            unit: bomItem.unit || 'EA',
            quantity: orderQty,
            base_quantity: baseQty,
            calculated_quantity: calcQty,
            unit_price: bomItem.unit_price,
            total_price: bomItem.unit_price * calcQty,
            sort_order: sortOrder++,
            note: [loc.floor, loc.code].filter(v => v && v !== '-').join(' ') || null,
            formula_source: `product_${locIndex}`,
            item_index: locIndex,
            finished_goods_code: loc.bomResult!.finished_goods.code,
            formula_category: bomItem.process_group || undefined,
          });
        });
      }
    });
  } else {
    // 완제품 기준 (BOM 산출 전)
    items = data.locations.map((loc, index) => ({
      item_name: loc.productName,
      item_code: loc.productCode,
      specification: loc.openWidth && loc.openHeight
        ? `${loc.openWidth}x${loc.openHeight}mm`
        : null,
      unit: '개소',
      quantity: loc.quantity,
      base_quantity: 1,
      calculated_quantity: loc.quantity,
      unit_price: loc.unitPrice || loc.inspectionFee || 0,
      total_price: loc.totalPrice || (loc.unitPrice || loc.inspectionFee || 0) * loc.quantity,
      sort_order: index + 1,
      note: [loc.floor, loc.code].filter(v => v && v !== '-').join(' ') || null,
      formula_source: `product_${index}`,
    }));
  }

  // 3. 총액 계산 (할인 반영)
  const totalSupply = items.reduce((sum, item) => sum + item.total_price, 0);
  const discountAmt = data.discountAmount || 0;
  const discountedSupply = totalSupply - discountAmt;
  const totalTax = Math.round(discountedSupply * 0.1);
  const grandTotal = discountedSupply + totalTax;

  // 4. API 요청 객체 반환
  return {
    registration_date: data.registrationDate,
    author: data.writer || null,
    client_id: data.clientId ? parseInt(data.clientId, 10) : null,
    client_name: data.clientName,
    site_name: data.siteName || null,
    manager: data.manager || null,
    contact: data.contact || null,
    completion_date: data.dueDate || null,
    remarks: data.remarks || null,
    product_category: deriveProductCategory(data.locations),
    quantity: data.locations.reduce((sum, loc) => sum + loc.quantity, 0),
    unit_symbol: '개소',
    total_amount: grandTotal,
    discount_rate: data.discountRate || 0,
    discount_amount: discountAmt,
    status: data.status === 'final' ? 'finalized' : 'draft',
    is_final: data.status === 'final',
    calculation_inputs: calculationInputs,
    options: {
      vat_type: data.vatType || 'included',
    },
    items: items,
  };
}

/**
 * API 응답 → V2 폼 데이터 변환
 *
 * 핵심:
 * - calculation_inputs.items가 있으면 그것으로 locations 복원
 * - 없으면 items에서 추출 시도 (레거시 호환)
 */
export function transformApiToV2(apiData: QuoteApiData): QuoteFormDataV2 {
  // 원본 API 데이터(calculation_inputs)와 변환된 데이터(calculationInputs) 모두 지원
  // getQuoteById가 transformApiToFrontend를 적용하면 calculationInputs(camelCase)가 됨
  const rawCalcInputs = apiData.calculation_inputs;
  const transformedCalcInputs = (apiData as unknown as { calculationInputs?: CalculationInputs & { bomResults?: BomCalculationResult[] } }).calculationInputs;
  const calculationInputs = rawCalcInputs || transformedCalcInputs;

  const calcInputs = calculationInputs?.items || [];
  // BOM 결과 복원 (저장 시 calculation_inputs.bomResults에 저장됨)
  const savedBomResults = (calculationInputs as { bomResults?: BomCalculationResult[] } | undefined)?.bomResults || [];

  // calculation_inputs에서 locations 복원
  let locations: LocationItem[] = [];

  if (calcInputs.length > 0) {
    locations = calcInputs.map((ci, index) => {
      const qty = ci.quantity || 1;

      // 해당 인덱스의 BOM 결과 복원
      const bomResult = savedBomResults[index];

      // 금액 계산: bomResult.grand_total 우선, 없으면 apiData.items에서 계산
      let unitPrice: number | undefined;
      let totalPrice: number | undefined;

      if (bomResult?.grand_total) {
        // BOM 결과에서 금액 가져오기
        unitPrice = Math.round(bomResult.grand_total);
        totalPrice = Math.round(bomResult.grand_total * qty);
      } else {
        // Fallback: apiData.items에서 계산
        const relatedItems = (apiData.items || []).filter(
          item => (item as QuoteItemApiData & { item_index?: number }).item_index === index ||
                  (item.note && ci.floor && item.note.includes(ci.floor))
        );
        const itemsTotal = relatedItems.reduce(
          (sum, item) => sum + parseFloat(String(item.total_price ?? item.total_amount ?? 0)), 0
        );
        if (itemsTotal > 0) {
          unitPrice = Math.round(itemsTotal / qty);
          totalPrice = itemsTotal;
        }
      }

      return {
        id: `loc-${index}`,
        floor: ci.floor || '',
        code: ci.code || '',
        openWidth: parseInt(ci.openWidth || '0', 10),
        openHeight: parseInt(ci.openHeight || '0', 10),
        productCode: (ci as { productCode?: string }).productCode || bomResult?.finished_goods?.code || '',
        productName: ci.productName || '',
        itemCategory: ci.itemCategory,
        quantity: qty,
        guideRailType: ci.guideRailType || 'wall',
        motorPower: ci.motorPower || 'single',
        controller: ci.controller || 'exposed',
        wingSize: parseInt(ci.wingSize || '50', 10),
        inspectionFee: ci.inspectionFee || 50000,
        unitPrice,
        totalPrice,
        bomResult: bomResult,  // BOM 결과 복원
      };
    });
  }

  // 상태 매핑
  const mapStatus = (s: string): 'draft' | 'temporary' | 'final' => {
    if (s === 'finalized' || s === 'converted') return 'final';
    return 'draft';
  };

  // 변환된 Quote 데이터 타입 (camelCase)
  const transformed = apiData as unknown as {
    quoteNumber?: string;
    registrationDate?: string;
    createdBy?: string;
    clientId?: string;
    clientName?: string;
    siteName?: string;
    managerName?: string;
    managerContact?: string;
    deliveryDate?: string;
    description?: string;
    discountRate?: number;
    discountAmount?: number;
    orderId?: number | null;  // 연결된 수주 ID (camelCase 버전)
  };

  return {
    id: String(apiData.id),
    quoteNumber: apiData.quote_number || transformed.quoteNumber || '',
    // raw API: registration_date, transformed: registrationDate
    registrationDate: formatDateForInput(apiData.registration_date || transformed.registrationDate),
    // raw API: creator?.name, transformed: createdBy
    writer: apiData.creator?.name || transformed.createdBy || '',
    // raw API: client_id, transformed: clientId
    clientId: apiData.client_id ? String(apiData.client_id) : (transformed.clientId || ''),
    // raw API: client?.name || client_name, transformed: clientName
    clientName: apiData.client?.name || apiData.client_name || transformed.clientName || '',
    // raw API: site_name, transformed: siteName
    siteName: apiData.site_name || transformed.siteName || '',
    // raw API: manager || manager_name, transformed: managerName
    manager: apiData.manager || apiData.manager_name || transformed.managerName || '',
    // raw API: contact || manager_contact, transformed: managerContact
    contact: apiData.contact || apiData.manager_contact || transformed.managerContact || '',
    // raw API: completion_date || delivery_date, transformed: deliveryDate
    dueDate: formatDateForInput(apiData.completion_date || apiData.delivery_date || transformed.deliveryDate),
    // raw API: remarks || description, transformed: description
    remarks: apiData.remarks || apiData.description || transformed.description || '',
    status: mapStatus(apiData.status),
    // raw API: discount_rate, transformed: discountRate
    vatType: apiData.options?.vat_type as 'included' | 'excluded'
      || (transformed as unknown as { vatType?: string })?.vatType as 'included' | 'excluded'
      || 'included',
    discountRate: Number(apiData.discount_rate) || transformed.discountRate || 0,
    discountAmount: Number(apiData.discount_amount) || transformed.discountAmount || 0,
    locations: locations,
    // 연결된 수주 ID (raw API: order_id, transformed: orderId)
    orderId: apiData.order_id ?? transformed.orderId ?? null,
    // 수정 가능 여부 (생산지시 존재 시 false)
    isEditable: (apiData as unknown as { is_editable?: boolean }).is_editable ?? true,
    hasWorkOrders: (apiData as unknown as { has_work_orders?: boolean }).has_work_orders ?? false,
  };
}

// ===== QuoteFormData → API 요청 데이터 변환 =====
export function transformFormDataToApi(formData: QuoteFormData): Record<string, unknown> {
  // calculationResults가 있으면 BOM 자재 기반으로 items 생성
  // 없으면 완제품 기준으로 items 생성 (기존 로직)
  let itemsData: Array<{
    item_name: string;
    item_code: string;
    specification: string | null;
    unit: string;
    quantity: number;
    base_quantity: number;
    calculated_quantity: number;
    unit_price: number;
    total_price: number;
    sort_order: number;
    note: string | null;
    formula_source?: string;
    item_index?: number;
    finished_goods_code?: string;
    formula_category?: string;
  }> = [];

  if (formData.calculationResults && formData.calculationResults.items.length > 0) {
    // BOM 자재 기반 items 생성
    let sortOrder = 1;

    formData.calculationResults.items.forEach((calcItem) => {
      const formItem = formData.items[calcItem.index];
      const orderQuantity = formItem?.quantity || 1;  // 주문 수량

      calcItem.result.items.forEach((bomItem) => {
        const baseQuantity = bomItem.quantity;  // 1개당 BOM 수량
        const calculatedQuantity = bomItem.unit === 'EA'
          ? Math.round(baseQuantity * orderQuantity)
          : parseFloat((baseQuantity * orderQuantity).toFixed(2));
        const totalPrice = bomItem.unit_price * calculatedQuantity;

        itemsData.push({
          item_name: bomItem.item_name,
          item_code: bomItem.item_code,
          specification: bomItem.specification || null,
          unit: bomItem.unit || 'EA',
          quantity: orderQuantity,  // 주문 수량
          base_quantity: baseQuantity,  // 1개당 BOM 수량
          calculated_quantity: calculatedQuantity,  // base × 주문 수량
          unit_price: bomItem.unit_price,
          total_price: totalPrice,
          sort_order: sortOrder++,
          note: [formItem?.floor, formItem?.code].filter(v => v && v !== '-').join(' ') || null,
          formula_source: `product_${calcItem.index}`,
          item_index: calcItem.index,
          finished_goods_code: calcItem.result.finished_goods.code,
          formula_category: bomItem.process_group || undefined,
        });
      });
    });
  } else {
    // 기존 로직: 완제품 기준 items 생성
    itemsData = formData.items.map((item, index) => {
      const unitPrice = item.unitPrice || item.inspectionFee || 0;
      const supplyAmount = unitPrice * item.quantity;

      return {
        item_name: item.productName,
        item_code: item.productName,
        specification: item.openWidth && item.openHeight
          ? `${item.openWidth}x${item.openHeight}mm`
          : null,
        unit: item.unit || '개소',  // 품목의 단위 사용, 없으면 '개소'
        quantity: item.quantity,
        base_quantity: 1,  // 완제품은 1개당 1개
        calculated_quantity: item.quantity,
        unit_price: unitPrice,
        total_price: supplyAmount,
        sort_order: index + 1,
        note: [item.floor, item.code].filter(v => v && v !== '-').join(' ') || null,
        formula_source: `product_${index}`,
      };
    });
  }

  // 총액 계산
  const totalSupply = itemsData.reduce((sum, item) => sum + item.total_price, 0);
  const totalTax = Math.round(totalSupply * 0.1);
  const grandTotal = totalSupply + totalTax;

  // 자동산출 입력값 저장 (나중에 폼 복원용)
  const calculationInputs: CalculationInputs = {
    items: formData.items.map(item => ({
      productCategory: item.productCategory,
      productName: item.productName,
      openWidth: item.openWidth,
      openHeight: item.openHeight,
      guideRailType: item.guideRailType,
      motorPower: item.motorPower,
      controller: item.controller,
      wingSize: item.wingSize,
      inspectionFee: item.inspectionFee,
      floor: item.floor,
      code: item.code,
      quantity: item.quantity,  // 수량도 저장
    })),
  };

  const result = {
    registration_date: formData.registrationDate,
    author: formData.writer || null,  // writer → author 필드 매핑
    client_id: formData.clientId ? parseInt(formData.clientId, 10) : null,
    client_name: formData.clientName,
    site_name: formData.siteName || null,
    manager: formData.manager || null,
    contact: formData.contact || null,
    completion_date: formData.dueDate || null,
    remarks: formData.remarks || null,
    product_category: formData.items[0]?.productCategory?.toUpperCase() || 'SCREEN',
    quantity: formData.items.reduce((sum, item) => sum + item.quantity, 0),
    unit_symbol: formData.unitSymbol || '개소',  // 선택한 제품의 단위 또는 기본값
    total_amount: grandTotal,
    calculation_inputs: calculationInputs,
    items: itemsData,
  };


  return result;
}