/**
 * 견적 등록/수정 컴포넌트 V2
 *
 * 새로운 레이아웃:
 * - 좌우 분할: 발주 개소 목록 | 선택 개소 상세
 * - 하단: 견적 금액 요약 (개소별 + 상세별)
 * - 푸터: 총 금액 + 버튼들 (견적서 산출, 임시저장, 최종저장)
 */

"use client";

import { useState, useEffect, useMemo, useCallback, useRef } from "react";
import { FileText, Calculator } from "lucide-react";
import { toast } from "sonner";

import { Card, CardContent, CardHeader, CardTitle } from "../ui/card";
import { Badge } from "../ui/badge";
import { Input } from "../ui/input";
import { DatePicker } from "../ui/date-picker";
import { PhoneInput } from "../ui/phone-input";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "../ui/select";
import { SearchableSelect } from "../ui/searchable-select";

import { LocationListPanel } from "./LocationListPanel";
import { LocationDetailPanel } from "./LocationDetailPanel";
import { QuoteSummaryPanel } from "./QuoteSummaryPanel";
import { QuoteFooterBar } from "./QuoteFooterBar";
import { QuotePreviewModal } from "./QuotePreviewModal";
import { QuoteTransactionModal } from "./QuoteTransactionModal";
import { DiscountModal } from "./DiscountModal";
import { FormulaViewModal } from "./FormulaViewModal";

import {
  getFinishedGoods,
  calculateBomBulk,
  getQuoteReferenceData,
  type FinishedGoods,
  type BomBulkResponse,
} from "./actions";
import type { BomCalculationResult } from "./types";
import { getClients } from "../accounting/VendorManagement/actions";
import { isNextRedirectError } from "@/lib/utils/redirect-error";
// 실제 로그인 사용자 정보는 localStorage('user')에 저장됨 (LoginPage.tsx 참조)
import { useDevFill } from "@/components/dev/useDevFill";
import type { Vendor } from "../accounting/VendorManagement";
import type { BomCalculationResultItem } from "./types";
import { getLocalDateString } from "@/lib/utils/date";
import { formatNumber } from "@/lib/utils/amount";

// =============================================================================
// 타입 정의
// =============================================================================

// 발주 개소 항목
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
export interface QuoteFormDataV2 {
  id?: string;
  quoteNumber: string; // 견적번호
  registrationDate: string; // 접수일
  writer: string; // 작성자
  clientId: string; // 수주처 ID
  clientName: string; // 수주처명
  siteName: string; // 현장명
  manager: string; // 담당자
  contact: string; // 연락처
  vatType: "included" | "excluded"; // 부가세 (포함/별도)
  remarks: string; // 비고
  status: "draft" | "temporary" | "final" | "converted"; // 작성중, 임시저장, 최종저장, 수주전환
  discountRate: number; // 할인율 (%)
  discountAmount: number; // 할인 금액
  locations: LocationItem[];
  orderId?: number | null; // 연결된 수주 ID (수주전환 시 설정)
  isEditable?: boolean; // 수정 가능 여부 (생산지시 존재 시 false)
  hasWorkOrders?: boolean; // 연결된 수주에 생산지시 존재 여부
}

// =============================================================================
// 상수
// =============================================================================

// 초기 개소 항목
const _createNewLocation = (): LocationItem => ({
  id: `loc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
  floor: "",
  code: "",
  openWidth: 0,
  openHeight: 0,
  productCode: "",
  productName: "",
  quantity: 1,
  guideRailType: "wall",
  motorPower: "single",
  controller: "exposed",
  wingSize: 50,
  inspectionFee: 50000,
});

// 초기 폼 데이터
const INITIAL_FORM_DATA: QuoteFormDataV2 = {
  quoteNumber: "", // 자동생성 또는 서버에서 부여
  registrationDate: getLocalDateString(new Date()),
  writer: "", // useAuth()에서 currentUser.name으로 설정됨
  clientId: "",
  clientName: "",
  siteName: "",
  manager: "",
  contact: "",
  vatType: "included", // 기본값: 부가세 포함
  remarks: "",
  status: "draft",
  discountRate: 0,
  discountAmount: 0,
  locations: [],
};

// =============================================================================
// Props
// =============================================================================

interface QuoteRegistrationProps {
  mode: "create" | "view" | "edit";
  onBack: () => void;
  onSave?: (data: QuoteFormDataV2, saveType: "temporary" | "final") => Promise<void>;
  onCalculate?: () => void;
  onEdit?: () => void;
  onOrderRegister?: () => void;
  /** 수주 보기 (이미 수주가 있는 경우) */
  onOrderView?: () => void;
  initialData?: QuoteFormDataV2 | null;
  isLoading?: boolean;
  /** IntegratedDetailTemplate 사용 시 타이틀 영역 숨김 */
  hideHeader?: boolean;
}

// =============================================================================
// 메인 컴포넌트
// =============================================================================

export function QuoteRegistration({
  mode,
  onBack,
  onSave,
  onCalculate: _onCalculate,
  onEdit,
  onOrderRegister,
  onOrderView,
  initialData,
  isLoading: _isLoading = false,
  hideHeader = false,
}: QuoteRegistrationProps) {
  // ---------------------------------------------------------------------------
  // 상태
  // ---------------------------------------------------------------------------
  const [formData, setFormData] = useState<QuoteFormDataV2>(
    initialData || INITIAL_FORM_DATA
  );
  const [selectedLocationId, setSelectedLocationId] = useState<string | null>(null);
  const [isSaving, setIsSaving] = useState(false);
  const [isCalculating, setIsCalculating] = useState(false);
  const [quotePreviewOpen, setQuotePreviewOpen] = useState(false);
  const [transactionPreviewOpen, setTransactionPreviewOpen] = useState(false);
  const [discountModalOpen, setDiscountModalOpen] = useState(false);
  const [formulaViewOpen, setFormulaViewOpen] = useState(false);
  // 할인율/할인금액은 formData에서 관리 (저장/로드 연동)
  const discountRate = formData.discountRate ?? 0;
  const discountAmount = formData.discountAmount ?? 0;
  const pendingAutoCalculateRef = useRef(false);

  // API 데이터
  const [clients, setClients] = useState<Vendor[]>([]);
  const [finishedGoods, setFinishedGoods] = useState<FinishedGoods[]>([]);
  const [siteNames, setSiteNames] = useState<string[]>([]);
  const [locationCodes, setLocationCodes] = useState<string[]>([]);
  const [isLoadingClients, setIsLoadingClients] = useState(false);
  const [, setIsLoadingProducts] = useState(false);

  // handleCalculate 참조 (DevFill에서 사용)
  const calculateRef = useRef<(() => Promise<void>) | null>(null);

  // 디버그용: formData를 window에 노출
  useEffect(() => {
    if (typeof window !== "undefined") {
      (window as unknown as { __QUOTE_DEBUG__: { formData: QuoteFormDataV2; selectedLocationId: string | null } }).__QUOTE_DEBUG__ = {
        formData,
        selectedLocationId,
      };
    }
  }, [formData, selectedLocationId]);

  // ---------------------------------------------------------------------------
  // DevFill (개발/테스트용 자동 채우기)
  // ---------------------------------------------------------------------------
  useDevFill("quoteV2", useCallback(() => {
    // 제품 1개 고정 선택 (모델별 인증이라 섞을 수 없음)
    const fixedProduct = finishedGoods.length > 0
      ? finishedGoods[Math.floor(Math.random() * finishedGoods.length)]
      : null;

    // 층 순서 (정렬된 상태로 순차 할당)
    const sortedFloors = ["B2", "B1", "1F", "2F", "3F", "4F", "5F", "R"];
    // 부호 접두사 1개 고정
    const codePrefixes = ["SD", "FSS", "FD", "SS", "DS"];
    const fixedPrefix = codePrefixes[Math.floor(Math.random() * codePrefixes.length)];

    // 가이드레일: 제품 specification에서 자동 추출
    const getGuideRailFromSpec = (spec?: string, name?: string): string => {
      const text = spec || name || '';
      if (text.includes('혼합')) return 'mixed';
      if (text.includes('측면')) return 'floor';
      if (text.includes('벽면')) return 'wall';
      return 'wall';
    };
    const motorPowers = ["single", "three"];
    const controllers = ["exposed", "embedded", "embedded_no_box"];

    // 1~5개 랜덤 개소 생성
    const locationCount = Math.floor(Math.random() * 5) + 1;

    // 층을 순차 할당할 시작 인덱스 (랜덤 시작점, 순서대로 올라감)
    const maxStartIdx = Math.max(0, sortedFloors.length - locationCount);
    const floorStartIdx = Math.floor(Math.random() * (maxStartIdx + 1));

    const testLocations: LocationItem[] = [];
    for (let i = 0; i < locationCount; i++) {
      const floorIdx = Math.min(floorStartIdx + i, sortedFloors.length - 1);
      const randomWidth = (Math.floor(Math.random() * 40) + 20) * 100;
      const randomHeight = (Math.floor(Math.random() * 30) + 20) * 100;

      testLocations.push({
        id: `loc-${Date.now()}-${i}`,
        floor: sortedFloors[floorIdx],
        code: `${fixedPrefix}-${String(i + 1).padStart(2, "0")}`,
        openWidth: randomWidth,
        openHeight: randomHeight,
        productCode: fixedProduct?.item_code || "FG-SCR-001",
        productName: fixedProduct?.item_name || "방화 스크린 셔터 (소형)",
        quantity: 1,
        guideRailType: getGuideRailFromSpec(fixedProduct?.specification, fixedProduct?.item_name),
        motorPower: motorPowers[Math.floor(Math.random() * motorPowers.length)],
        controller: controllers[Math.floor(Math.random() * controllers.length)],
        wingSize: [50, 60, 70][Math.floor(Math.random() * 3)],
        inspectionFee: [50000, 60000, 70000][Math.floor(Math.random() * 3)],
      });
    }

    // 로그인 사용자 정보 가져오기
    let writerName = "";
    try {
      const userStr = localStorage.getItem("user");
      if (userStr) {
        const user = JSON.parse(userStr);
        writerName = user?.name || "";
      }
    } catch (e) {
      console.error("[DevFill] 사용자 정보 로드 실패:", e);
    }

    const testData: QuoteFormDataV2 = {
      quoteNumber: "",
      registrationDate: getLocalDateString(new Date()),
      writer: writerName,
      clientId: clients[0]?.id?.toString() || "",
      clientName: clients[0]?.vendorName || "테스트 거래처",
      siteName: "테스트 현장",
      manager: "홍길동",
      contact: "010-1234-5678",
      vatType: "included",
      remarks: "[DevFill] 테스트 견적입니다.",
      status: "draft",
      discountRate: 0,
      discountAmount: 0,
      locations: testLocations,
    };

    setFormData(testData);
    setSelectedLocationId(testLocations[0].id);
    toast.success(`[DevFill] 테스트 데이터가 채워졌습니다. (${locationCount}개 개소)`);

    // 자동 견적 산출 트리거
    pendingAutoCalculateRef.current = true;
  }, [clients, finishedGoods]));

  // ---------------------------------------------------------------------------
  // 계산된 값
  // ---------------------------------------------------------------------------

  // 선택된 개소
  const selectedLocation = useMemo(() => {
    return formData.locations.find((loc) => loc.id === selectedLocationId) || null;
  }, [formData.locations, selectedLocationId]);

  // 총 금액 (할인 전)
  const totalAmount = useMemo(() => {
    return formData.locations.reduce((sum, loc) => sum + (loc.totalPrice || 0), 0);
  }, [formData.locations]);

  // 할인 적용 후 총 금액
  const discountedTotalAmount = useMemo(() => {
    return totalAmount - discountAmount;
  }, [totalAmount, discountAmount]);

  // 할인 적용 핸들러
  const handleApplyDiscount = useCallback((rate: number, amount: number) => {
    setFormData(prev => ({ ...prev, discountRate: rate, discountAmount: amount }));
    toast.success(`할인이 적용되었습니다. (${rate.toFixed(1)}%, ${formatNumber(amount)}원)`);
  }, []);

  // 개소별 합계
  const _locationTotals = useMemo(() => {
    return formData.locations.map((loc) => ({
      id: loc.id,
      label: `${loc.floor} / ${loc.code}`,
      productCode: loc.productCode,
      quantity: loc.quantity,
      unitPrice: loc.unitPrice || 0,
      totalPrice: loc.totalPrice || 0,
    }));
  }, [formData.locations]);

  // BOM 결과 유무
  const hasBomResult = useMemo(() => {
    return formData.locations.some((loc) => loc.bomResult);
  }, [formData.locations]);

  // ---------------------------------------------------------------------------
  // 작성자 자동 설정 (create 모드에서 로그인 사용자 정보 로드)
  // ---------------------------------------------------------------------------
  useEffect(() => {
    if (mode === "create" && !formData.writer) {
      // 실제 로그인 사용자 정보는 localStorage('user')에 저장됨
      try {
        const userStr = localStorage.getItem("user");
        if (userStr) {
          const user = JSON.parse(userStr);
          if (user?.name) {
            setFormData((prev) => ({ ...prev, writer: user.name }));
          }
        }
      } catch (e) {
        console.error("[QuoteRegistration] 사용자 정보 로드 실패:", e);
      }
    }
  }, [mode, formData.writer]);

  // ---------------------------------------------------------------------------
  // 초기 데이터 로드
  // ---------------------------------------------------------------------------

  useEffect(() => {
    const loadInitialData = async () => {
      // 거래처 로드
      setIsLoadingClients(true);
      try {
        const result = await getClients({ size: 200, only_active: true });
        if (result.success) {
          setClients(result.data);
        }
      } catch (error) {
        if (isNextRedirectError(error)) throw error;
        console.error("거래처 로드 실패:", error);
      } finally {
        setIsLoadingClients(false);
      }

      // 완제품 로드
      setIsLoadingProducts(true);
      try {
        const result = await getFinishedGoods();
        if (result.success) {
          setFinishedGoods(result.data);
        }
      } catch (error) {
        if (isNextRedirectError(error)) throw error;
        console.error("완제품 로드 실패:", error);
      } finally {
        setIsLoadingProducts(false);
      }

      // 참조 데이터 로드 (현장명, 부호)
      try {
        const result = await getQuoteReferenceData();
        if (result.success) {
          setSiteNames(result.data.siteNames);
          setLocationCodes(result.data.locationCodes);
        }
      } catch (error) {
        if (isNextRedirectError(error)) throw error;
      }
    };

    loadInitialData();
  }, []);

  // initialData 변경 시 formData 업데이트
  useEffect(() => {
    if (initialData) {
      setFormData(initialData);
      // 첫 번째 개소 자동 선택
      if (initialData.locations.length > 0 && !selectedLocationId) {
        setSelectedLocationId(initialData.locations[0].id);
      }
    }
  }, [initialData]);

  // ---------------------------------------------------------------------------
  // 핸들러
  // ---------------------------------------------------------------------------

  // 기본 정보 변경
  const handleFieldChange = useCallback((field: keyof QuoteFormDataV2, value: string) => {
    setFormData((prev) => ({ ...prev, [field]: value }));
  }, []);

  // 개소 추가 (BOM 계산 성공 시에만 추가, 성공/실패 반환)
  const handleAddLocation = useCallback(async (location: Omit<LocationItem, "id">): Promise<boolean> => {
    const newLocation: LocationItem = {
      ...location,
      id: `loc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
    };

    // BOM 계산 필수 조건 체크
    if (!newLocation.productCode || newLocation.openWidth <= 0 || newLocation.openHeight <= 0) {
      toast.error("제품, 가로, 세로를 모두 입력해주세요.");
      return false;
    }

    // 동일 모델만 등록 가능 (예: KSS01 → KSS01 변형만)
    if (formData.locations.length > 0) {
      const existingModel = formData.locations[0].productCode?.split('-')[1];
      const newModel = newLocation.productCode?.split('-')[1];
      if (existingModel && newModel && existingModel !== newModel) {
        toast.error(`동일 모델만 등록 가능합니다. 현재 모델: ${existingModel}`);
        return false;
      }
    }

    // 먼저 BOM 계산 API 호출
    try {
      const bomItem = {
        finished_goods_code: newLocation.productCode,
        openWidth: newLocation.openWidth,
        openHeight: newLocation.openHeight,
        quantity: newLocation.quantity,
        guideRailType: newLocation.guideRailType,
        motorPower: newLocation.motorPower,
        controller: newLocation.controller,
        wingSize: newLocation.wingSize,
        inspectionFee: newLocation.inspectionFee,
      };

      const result = await calculateBomBulk([bomItem]);

      if (result.success && result.data) {
        const apiData = result.data as BomBulkResponse;
        const bomResponseItems = apiData.items || [];
        const bomResult = bomResponseItems[0]?.result;

        if (bomResult) {
          // BOM 계산 성공 시에만 개소 추가
          const locationWithBom: LocationItem = {
            ...newLocation,
            unitPrice: bomResult.grand_total,
            totalPrice: bomResult.grand_total * newLocation.quantity,
            bomResult: bomResult,
          };

          setFormData((prev) => ({
            ...prev,
            locations: [...prev.locations, locationWithBom],
          }));
          setSelectedLocationId(newLocation.id);
          toast.success("개소가 추가되고 BOM이 계산되었습니다.");
          return true;
        }
      }

      // API 에러 메시지 표시 (개소 추가 안 함)
      toast.error(result.error || "BOM 계산 실패 - 개소가 추가되지 않았습니다.");
      return false;
    } catch (error) {
      console.error("[handleAddLocation] BOM 계산 실패:", error);
      toast.error("BOM 계산 중 오류가 발생했습니다.");
      return false;
    }
  }, []);

  // 개소 삭제
  // 개소 복제 (부호 자동 채번)
  const handleCloneLocation = useCallback((locationId: string) => {
    const source = formData.locations.find((loc) => loc.id === locationId);
    if (!source) return;

    // 층/부호가 없거나 "-"이면 그대로 유지
    let newFloor = source.floor || "-";
    let newCode = source.code || "-";

    if (newCode !== "-") {
      // 부호에서 접두어와 번호 분리 (예: "DS-01" → prefix="DS-", num=1)
      const codeMatch = source.code.match(/^(.*?)(\d+)$/);
      if (codeMatch) {
        const prefix = codeMatch[1]; // "DS-"
        const numLength = codeMatch[2].length; // 2 (자릿수 보존)

        // 같은 접두어를 가진 부호 중 최대 번호 찾기
        let maxNum = 0;
        formData.locations.forEach((loc) => {
          const m = loc.code.match(new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(\\d+)$`));
          if (m) {
            maxNum = Math.max(maxNum, parseInt(m[1], 10));
          }
        });

        newCode = prefix + String(maxNum + 1).padStart(numLength, "0");
      } else {
        newCode = source.code + "-copy";
      }
    }

    const clonedLocation: LocationItem = {
      ...source,
      id: `loc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
      floor: newFloor,
      code: newCode,
    };

    setFormData((prev) => ({
      ...prev,
      locations: [...prev.locations, clonedLocation],
    }));
    setSelectedLocationId(clonedLocation.id);
    toast.success(`개소가 복제되었습니다. (${newCode})`);
  }, [formData.locations]);

  // 개소 삭제
  const handleDeleteLocation = useCallback((locationId: string) => {
    setFormData((prev) => ({
      ...prev,
      locations: prev.locations.filter((loc) => loc.id !== locationId),
    }));
    if (selectedLocationId === locationId) {
      setSelectedLocationId(formData.locations[0]?.id || null);
    }
    toast.success("개소가 삭제되었습니다.");
  }, [selectedLocationId, formData.locations]);

  // 개소 수정
  const handleUpdateLocation = useCallback((locationId: string, updates: Partial<LocationItem>) => {
    setFormData((prev) => ({
      ...prev,
      locations: prev.locations.map((loc) =>
        loc.id === locationId ? { ...loc, ...updates } : loc
      ),
    }));
  }, []);

  // 엑셀 업로드
  const handleExcelUpload = useCallback((locations: Omit<LocationItem, "id">[]) => {
    const newLocations: LocationItem[] = locations.map((loc) => ({
      ...loc,
      id: `loc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
    }));
    setFormData((prev) => ({
      ...prev,
      locations: [...prev.locations, ...newLocations],
    }));
    if (newLocations.length > 0) {
      setSelectedLocationId(newLocations[0].id);
    }
    toast.success(`${newLocations.length}개 개소가 추가되었습니다.`);
  }, []);

  // 견적 산출
  const handleCalculate = useCallback(async () => {
    if (formData.locations.length === 0) {
      toast.error("산출할 개소가 없습니다.");
      return;
    }

    setIsCalculating(true);
    try {
      const bomItems = formData.locations.map((loc) => ({
        finished_goods_code: loc.productCode,
        openWidth: loc.openWidth,
        openHeight: loc.openHeight,
        quantity: loc.quantity,
        guideRailType: loc.guideRailType,
        motorPower: loc.motorPower,
        controller: loc.controller,
        wingSize: loc.wingSize,
        inspectionFee: loc.inspectionFee,
      }));

      const result = await calculateBomBulk(bomItems);

      if (result.success && result.data) {
        // API 응답: { success, summary: { grand_total, ... }, items: [{ index, result: BomCalculationResult }] }
        const apiData = result.data as BomBulkResponse;
        const bomResponseItems = apiData.items || [];


        // 결과 반영 (수동 추가 품목 보존)
        const updatedLocations = formData.locations.map((loc, index) => {
          const bomItem = bomResponseItems.find((item) => item.index === index);
          const bomResult = bomItem?.result;
          if (bomResult) {
            // 기존 수동 추가 품목 추출 (is_manual: true)
            const manualItems = (loc.bomResult?.items || []).filter(
              (item: BomCalculationResultItem & { is_manual?: boolean }) => item.is_manual === true
            );

            // 수동 추가 품목의 총 금액
            const manualTotal = manualItems.reduce(
              (sum: number, item: BomCalculationResultItem) => sum + (item.total_price || 0),
              0
            );

            // 새 BOM 결과에 수동 품목 병합
            const mergedItems = [...(bomResult.items || []), ...manualItems];
            const mergedGrandTotal = bomResult.grand_total + manualTotal;


            return {
              ...loc,
              unitPrice: mergedGrandTotal,
              totalPrice: mergedGrandTotal * loc.quantity,
              bomResult: {
                ...bomResult,
                items: mergedItems,
                grand_total: mergedGrandTotal,
              },
            };
          }
          return loc;
        });

        setFormData((prev) => ({ ...prev, locations: updatedLocations }));
        toast.success(`${formData.locations.length}개 개소의 견적이 산출되었습니다.`);
      } else {
        toast.error(`견적 산출 실패: ${result.error}`);
      }
    } catch (error) {
      if (isNextRedirectError(error)) throw error;
      toast.error("견적 산출 중 오류가 발생했습니다.");
    } finally {
      setIsCalculating(false);
    }
  }, [formData.locations]);

  // handleCalculate 참조 업데이트
  useEffect(() => {
    calculateRef.current = handleCalculate;
  }, [handleCalculate]);

  // DevFill 후 자동 견적 산출
  useEffect(() => {
    if (pendingAutoCalculateRef.current && formData.locations.length > 0) {
      pendingAutoCalculateRef.current = false;
      // 상태 업데이트 완료 후 산출 실행
      setTimeout(() => {
        handleCalculate();
      }, 50);
    }
  }, [formData.locations, handleCalculate]);

  // 저장 (임시/최종)
  const handleSave = useCallback(async (saveType: "temporary" | "final") => {
    if (!onSave) return;

    // 확정 시 필수 필드 밸리데이션
    if (saveType === "final") {
      const missing: string[] = [];
      if (!formData.clientName?.trim()) missing.push("업체명");
      if (!formData.siteName?.trim()) missing.push("현장명");
      if (!formData.manager?.trim()) missing.push("담당자");
      if (!formData.contact?.trim()) missing.push("연락처");
      if (missing.length > 0) {
        toast.error(`견적확정을 위해 다음 항목을 입력해주세요: ${missing.join(", ")}`);
        return;
      }
    }

    setIsSaving(true);
    try {
      const dataToSave: QuoteFormDataV2 = {
        ...formData,
        status: saveType === "temporary" ? "temporary" : "final",
      };
      await onSave(dataToSave, saveType);
      // 확정 성공 시 상태 즉시 반영 → 견적확정 버튼 → 수주등록 버튼으로 전환
      if (saveType === "final") {
        setFormData(prev => ({ ...prev, status: "final" }));
      }
    } catch (error) {
      if (isNextRedirectError(error)) throw error;
      const message = error instanceof Error ? error.message : "저장 중 오류가 발생했습니다.";
      toast.error(message);
    } finally {
      setIsSaving(false);
    }
  }, [formData, onSave]);

  // ---------------------------------------------------------------------------
  // 렌더링
  // ---------------------------------------------------------------------------

  const isViewMode = mode === "view";
  const pageTitle = mode === "create" ? "견적 등록 (V2 테스트)" : mode === "edit" ? "견적 수정 (V2 테스트)" : "견적 상세 (V2 테스트)";

  return (
    <div className="flex flex-col h-full">
      {/* 기본 정보 섹션 */}
      <div className={hideHeader ? "space-y-6" : "p-4 md:p-6 space-y-6"}>
        {/* 타이틀 영역 - hideHeader 시 IntegratedDetailTemplate이 담당 */}
        {!hideHeader && (
          <div className="flex items-center justify-between">
            <h1 className="text-2xl font-bold flex items-center gap-2">
              <FileText className="h-6 w-6" />
              {pageTitle}
            </h1>
            <Badge variant={formData.status === "final" ? "default" : formData.status === "temporary" ? "secondary" : "outline"}>
              {formData.status === "final" ? "견적 확정" : formData.status === "temporary" ? "저장됨" : "작성중"}
            </Badge>
          </div>
        )}

        {/* 기본 정보 */}
        <Card>
          <CardHeader className="pb-3">
            <CardTitle className="text-base font-semibold flex items-center gap-2">
              <FileText className="h-5 w-5" />
              기본 정보
            </CardTitle>
          </CardHeader>
          <CardContent className="space-y-4">
            {/* 1행: 견적번호 | 접수일 | 수주처 | 현장명 */}
            <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
              <div>
                <label className="text-sm font-medium text-gray-700">견적번호</label>
                <Input
                  value={formData.quoteNumber || "-"}
                  disabled
                  className="bg-gray-50"
                />
              </div>
              <div>
                <label className="text-sm font-medium text-gray-700">접수일</label>
                <DatePicker
                  value={formData.registrationDate}
                  onChange={(date) => handleFieldChange("registrationDate", date)}
                  disabled={isViewMode}
                />
              </div>
              <div>
                <label className="text-sm font-medium text-gray-700">수주처 <span className="text-red-500">*</span></label>
                <SearchableSelect
                  options={clients.map((c) => ({ value: c.id, label: c.vendorName }))}
                  value={formData.clientId}
                  onChange={(value, option) => {
                    const selectedClient = clients.find((c) => c.id === value);
                    setFormData((prev) => ({
                      ...prev,
                      clientId: value,
                      clientName: option.label,
                      manager: selectedClient?.managerName || selectedClient?.representativeName || prev.manager,
                      contact: selectedClient?.managerPhone || selectedClient?.mobile || selectedClient?.phone || prev.contact,
                    }));
                  }}
                  placeholder={isLoadingClients ? "로딩 중..." : "수주처를 선택하세요"}
                  searchPlaceholder="수주처 검색..."
                  emptyText="수주처가 없습니다"
                  disabled={isViewMode || isLoadingClients}
                  isLoading={isLoadingClients}
                />
              </div>
              <div>
                <label className="text-sm font-medium text-gray-700">현장명</label>
                <SearchableSelect
                  options={siteNames.map((name) => ({ value: name, label: name }))}
                  value={formData.siteName}
                  onChange={(value) => handleFieldChange("siteName", value)}
                  placeholder="현장명을 선택 또는 입력하세요"
                  searchPlaceholder="현장명 검색 또는 입력..."
                  emptyText="현장명이 없습니다"
                  disabled={isViewMode}
                  creatable
                  creatableText="직접 입력"
                />
              </div>
            </div>

            {/* 2행: 담당자 | 연락처 | 작성자 | 부가세 */}
            <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
              <div>
                <label className="text-sm font-medium text-gray-700">담당자</label>
                <Input
                  placeholder="담당자명을 입력하세요"
                  value={formData.manager}
                  onChange={(e) => handleFieldChange("manager", e.target.value)}
                  disabled={isViewMode}
                />
              </div>
              <div>
                <label className="text-sm font-medium text-gray-700">연락처</label>
                <PhoneInput
                  placeholder="010-1234-5678"
                  value={formData.contact}
                  onChange={(value) => handleFieldChange("contact", value)}
                  disabled={isViewMode}
                />
              </div>
              <div>
                <label className="text-sm font-medium text-gray-700">작성자</label>
                <Input
                  value={formData.writer}
                  disabled
                  className="bg-gray-50"
                />
              </div>
              <div>
                <label className="text-sm font-medium text-gray-700">부가세</label>
                <Select
                  value={formData.vatType}
                  onValueChange={(value) => handleFieldChange("vatType", value)}
                  disabled={isViewMode}
                >
                  <SelectTrigger>
                    <SelectValue placeholder="부가세 선택" />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="included">부가세 포함</SelectItem>
                    <SelectItem value="excluded">부가세 별도</SelectItem>
                  </SelectContent>
                </Select>
              </div>
            </div>

            {/* 3행: 상태 | 비고 */}
            <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
              <div>
                <label className="text-sm font-medium text-gray-700">상태</label>
                <Input
                  value={formData.status === "final" ? "견적완료" : formData.status === "temporary" ? "임시저장" : "최초작성"}
                  disabled
                  className="bg-gray-50"
                />
              </div>
              <div className="md:col-span-3">
                <label className="text-sm font-medium text-gray-700">비고</label>
                <Input
                  placeholder="특이사항을 입력하세요"
                  value={formData.remarks}
                  onChange={(e) => handleFieldChange("remarks", e.target.value)}
                  disabled={isViewMode}
                />
              </div>
            </div>
          </CardContent>
        </Card>

        {/* 자동 견적 산출 섹션 */}
        <Card>
          <CardHeader className="pb-3">
            <CardTitle className="text-base font-semibold flex items-center gap-2">
              <Calculator className="h-5 w-5" />
              자동 견적 산출
            </CardTitle>
          </CardHeader>
          <CardContent className="p-0">
            {/* 좌우 분할 레이아웃 */}
            <div className="grid grid-cols-1 lg:grid-cols-2 min-h-[500px]">
              {/* 왼쪽: 발주 개소 목록 + 추가 폼 */}
              <LocationListPanel
                locations={formData.locations}
                selectedLocationId={selectedLocationId}
                onSelectLocation={setSelectedLocationId}
                onAddLocation={handleAddLocation}
                onDeleteLocation={handleDeleteLocation}
                onCloneLocation={handleCloneLocation}
                onUpdateLocation={handleUpdateLocation}
                onExcelUpload={handleExcelUpload}
                finishedGoods={finishedGoods}
                locationCodes={locationCodes}
                disabled={isViewMode}
              />

              {/* 오른쪽: 선택 개소 상세 */}
              <LocationDetailPanel
                location={selectedLocation}
                onUpdateLocation={handleUpdateLocation}
                onDeleteLocation={handleDeleteLocation}
                locationCodes={locationCodes}
                onCalculateLocation={async (locationId) => {
                  // 단일 개소 산출
                  const location = formData.locations.find((loc) => loc.id === locationId);
                  if (!location) return;

                  setIsCalculating(true);
                  try {
                    const bomItem = {
                      finished_goods_code: location.productCode,
                      openWidth: location.openWidth,
                      openHeight: location.openHeight,
                      quantity: location.quantity,
                      guideRailType: location.guideRailType,
                      motorPower: location.motorPower,
                      controller: location.controller,
                      wingSize: location.wingSize,
                      inspectionFee: location.inspectionFee,
                    };

                    const result = await calculateBomBulk([bomItem]);

                    if (result.success && result.data) {
                      const apiData = result.data as BomBulkResponse;
                      const bomResult = apiData.items?.[0]?.result;

                      if (bomResult) {
                        handleUpdateLocation(locationId, {
                          unitPrice: bomResult.grand_total,
                          totalPrice: bomResult.grand_total * location.quantity,
                          bomResult: bomResult,
                        });
                        toast.success("견적이 산출되었습니다.");
                      }
                    } else {
                      toast.error(result.error || "산출 실패");
                    }
                  } catch (error) {
                    console.error("산출 오류:", error);
                    toast.error("산출 중 오류가 발생했습니다.");
                  } finally {
                    setIsCalculating(false);
                  }
                }}
                onSaveItems={() => {
                  toast.success("품목이 저장되었습니다.");
                }}
                finishedGoods={finishedGoods}
                disabled={isViewMode}
                isCalculating={isCalculating}
              />
            </div>
          </CardContent>
        </Card>

        {/* 견적 금액 요약 */}
        <QuoteSummaryPanel
          locations={formData.locations}
          selectedLocationId={selectedLocationId}
          onSelectLocation={setSelectedLocationId}
          discountedTotalAmount={discountedTotalAmount}
        />
      </div>

      {/* 푸터 바 (고정) */}
      <QuoteFooterBar
        totalLocations={formData.locations.length}
        totalAmount={discountedTotalAmount}
        status={formData.status}
        onQuoteView={() => setQuotePreviewOpen(true)}
        onTransactionView={() => setTransactionPreviewOpen(true)}
        onSave={() => handleSave("temporary")}
        onFinalize={() => handleSave("final")}
        onBack={onBack}
        onCancel={onBack}
        onEdit={onEdit}
        onOrderRegister={onOrderRegister}
        onOrderView={onOrderView}
        orderId={formData.orderId}
        isEditable={formData.isEditable}
        hasWorkOrders={formData.hasWorkOrders}
        onDiscount={() => setDiscountModalOpen(true)}
        onFormulaView={() => setFormulaViewOpen(true)}
        hasBomResult={hasBomResult}
        isSaving={isSaving}
        isViewMode={isViewMode}
      />

      {/* 견적서 보기 모달 */}
      <QuotePreviewModal
        open={quotePreviewOpen}
        onOpenChange={setQuotePreviewOpen}
        quoteData={formData}
        discountRate={discountRate}
        discountAmount={discountAmount}
      />

      {/* 거래명세서 보기 모달 */}
      <QuoteTransactionModal
        open={transactionPreviewOpen}
        onOpenChange={setTransactionPreviewOpen}
        quoteData={formData}
        discountRate={discountRate}
        discountAmount={discountAmount}
      />

      {/* 할인하기 모달 */}
      <DiscountModal
        open={discountModalOpen}
        onOpenChange={setDiscountModalOpen}
        supplyAmount={totalAmount}
        initialDiscountRate={discountRate}
        initialDiscountAmount={discountAmount}
        onApply={handleApplyDiscount}
      />

      {/* 수식보기 모달 */}
      <FormulaViewModal
        open={formulaViewOpen}
        onOpenChange={setFormulaViewOpen}
        locations={formData.locations}
      />
    </div>
  );
}
