"use client";

import React, { useEffect, useState, useCallback, useMemo, useRef } from "react";
import { ComponentRendererProps } from "@/types/component";
import {
  Loader2,
  Package,
  TrendingUp,
  Warehouse,
  CheckCircle,
  Factory,
  Truck,
} from "lucide-react";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { toast } from "sonner";
import {
  ShippingPlanEditorConfig,
  ItemGroup,
  PlanDetailRow,
  ItemAggregation,
} from "./types";
import { getShippingPlanAggregate, batchSaveShippingPlans } from "@/lib/api/shipping";

export interface ShippingPlanEditorComponentProps
  extends ComponentRendererProps {}

export const ShippingPlanEditorComponent: React.FC<
  ShippingPlanEditorComponentProps
> = ({ component, isDesignMode = false, groupedData, formData, onFormDataChange, onClose, ...props }) => {
  const config = (component?.componentConfig ||
    {}) as ShippingPlanEditorConfig;
  const [itemGroups, setItemGroups] = useState<ItemGroup[]>([]);
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [source, setSource] = useState<"master" | "detail">("detail");
  const itemGroupsRef = useRef<ItemGroup[]>([]);
  const sourceRef = useRef<"master" | "detail">("detail");

  // groupedData에서 선택된 행 추출 (마스터든 디테일이든 그대로)
  const selectedRows = useMemo(() => {
    if (!groupedData) return [];
    if (Array.isArray(groupedData)) return groupedData;
    if (groupedData.selectedRows) return groupedData.selectedRows;
    if (groupedData.data) return groupedData.data;
    return [];
  }, [groupedData]);

  // 선택된 행의 ID 목록 추출 (문자열)
  const selectedIds = useMemo(() => {
    return selectedRows
      .map((row: any) => String(row.id))
      .filter((id: string) => id && id !== "undefined" && id !== "null");
  }, [selectedRows]);

  const loadData = useCallback(async () => {
    if (selectedIds.length === 0 || isDesignMode) return;

    setLoading(true);
    try {
      // ID만 보내면 백엔드에서 소스 감지 + JOIN + 정규화
      const res = await getShippingPlanAggregate(selectedIds);

      if (!res.success) {
        toast.error("집계 데이터 조회 실패");
        return;
      }

      setSource(res.source);
      const aggregateData = res.data || {};

      const groups: ItemGroup[] = Object.entries(aggregateData).map(
        ([partCode, data]) => {
          const details: PlanDetailRow[] = [];

          // 수주별로 기존 계획 합산량 계산
          const existingPlansBySource = new Map<string, number>();
          for (const plan of data.existingPlans || []) {
            const prev = existingPlansBySource.get(plan.sourceId) || 0;
            existingPlansBySource.set(plan.sourceId, prev + plan.planQty);
          }

          // 신규 행 먼저: 모든 수주에 대해 항상 추가 (분할출하 대응)
          for (const order of data.orders || []) {
            const alreadyPlanned = existingPlansBySource.get(order.sourceId) || 0;
            const remainingBalance = Math.max(0, order.balanceQty - alreadyPlanned);
            details.push({
              type: "new",
              sourceId: order.sourceId,
              orderNo: order.orderNo,
              partnerName: order.partnerName,
              dueDate: order.dueDate,
              balanceQty: remainingBalance,
              planQty: 0,
            });
          }

          // 기존 출하계획 아래에 표시
          for (const plan of data.existingPlans || []) {
            const matchOrder = data.orders?.find(
              (o) => o.sourceId === plan.sourceId
            );
            details.push({
              type: "existing",
              sourceId: plan.sourceId,
              orderNo: matchOrder?.orderNo || "-",
              partnerName: matchOrder?.partnerName || "-",
              dueDate: matchOrder?.dueDate || "-",
              balanceQty: matchOrder?.balanceQty || 0,
              planQty: plan.planQty,
              existingPlanId: plan.id,
            });
          }

          // partName: orders에서 가져오기
          const partName =
            data.orders?.[0]?.partName || partCode;

          return {
            partCode,
            partName,
            aggregation: {
              totalBalance: data.totalBalance,
              totalPlanQty: data.totalPlanQty,
              currentStock: data.currentStock,
              availableStock: data.availableStock,
              inProductionQty: data.inProductionQty,
            },
            details,
          };
        }
      );

      setItemGroups(groups);
    } catch (err) {
      console.error("[v2-shipping-plan-editor] 데이터 로드 실패:", err);
      toast.error("데이터를 불러오는데 실패했습니다");
    } finally {
      setLoading(false);
    }
  }, [selectedIds, isDesignMode]);

  useEffect(() => {
    loadData();
  }, [loadData]);

  // ref 동기화 (이벤트 핸들러에서 최신 state 접근용)
  useEffect(() => {
    itemGroupsRef.current = itemGroups;
  }, [itemGroups]);

  useEffect(() => {
    sourceRef.current = source;
  }, [source]);

  // 저장 로직 (ref 기반으로 최신 state 접근, 재구독 방지)
  const savingRef = useRef(false);
  const onCloseRef = useRef(onClose);
  onCloseRef.current = onClose;

  const configRef = useRef(config);
  configRef.current = config;

  const handleSave = useCallback(async () => {
    if (savingRef.current) return;

    const currentGroups = itemGroupsRef.current;
    const currentSource = sourceRef.current;
    const currentConfig = configRef.current;

    const plans = currentGroups.flatMap((g) =>
      g.details
        .filter((d) => d.type === "new" && d.planQty > 0)
        .map((d) => ({ sourceId: d.sourceId, planQty: d.planQty, balanceQty: d.balanceQty }))
    );

    if (plans.length === 0) {
      toast.warning("저장할 출하계획이 없습니다. 수량을 입력해주세요.");
      return;
    }

    // 잔량 초과 검증 (allowOverPlan = false일 때)
    if (!currentConfig.allowOverPlan) {
      const overPlan = plans.find((p) => p.balanceQty > 0 && p.planQty > p.balanceQty);
      if (overPlan) {
        toast.error("출하계획량이 미출하량을 초과합니다.");
        return;
      }
    }

    // 저장 전 확인 (confirmBeforeSave = true일 때)
    if (currentConfig.confirmBeforeSave) {
      const msg = currentConfig.confirmMessage || "출하계획을 저장하시겠습니까?";
      if (!window.confirm(msg)) return;
    }

    savingRef.current = true;
    setSaving(true);
    try {
      const savePlans = plans.map((p) => ({ sourceId: p.sourceId, planQty: p.planQty }));
      const res = await batchSaveShippingPlans(savePlans, currentSource);
      if (res.success) {
        toast.success(`${plans.length}건의 출하계획이 저장되었습니다.`);
        if (currentConfig.autoCloseOnSave !== false && onCloseRef.current) {
          onCloseRef.current();
        }
      } else {
        toast.error(res.error || "출하계획 저장에 실패했습니다.");
      }
    } catch (err) {
      console.error("[v2-shipping-plan-editor] 저장 실패:", err);
      toast.error("출하계획 저장 중 오류가 발생했습니다.");
    } finally {
      savingRef.current = false;
      setSaving(false);
    }
  }, []);

  // V2 이벤트 버스 구독 (마운트 1회만, ref로 최신 핸들러 참조)
  const handleSaveRef = useRef(handleSave);
  handleSaveRef.current = handleSave;

  useEffect(() => {
    let unsubscribe: (() => void) | null = null;
    let mounted = true;

    (async () => {
      const { v2EventBus, V2_EVENTS } = await import("@/lib/v2-core");
      if (!mounted) return;
      unsubscribe = v2EventBus.subscribe(V2_EVENTS.SHIPPING_PLAN_SAVE, () => {
        handleSaveRef.current();
      });
    })();

    return () => {
      mounted = false;
      if (unsubscribe) unsubscribe();
    };
  }, []);

  const handlePlanQtyChange = useCallback(
    (groupIdx: number, detailIdx: number, value: string) => {
      setItemGroups((prev) => {
        const next = [...prev];
        const group = { ...next[groupIdx] };
        const details = [...group.details];
        const detail = { ...details[detailIdx] };

        detail.planQty = Number(value) || 0;
        details[detailIdx] = detail;
        group.details = details;

        const newPlanTotal = details
          .filter((d) => d.type === "new")
          .reduce((sum, d) => sum + d.planQty, 0);
        const existingPlanTotal = details
          .filter((d) => d.type === "existing")
          .reduce((sum, d) => sum + d.planQty, 0);

        group.aggregation = {
          ...group.aggregation,
          totalPlanQty: existingPlanTotal + newPlanTotal,
          availableStock:
            group.aggregation.currentStock -
            (existingPlanTotal + newPlanTotal),
        };

        next[groupIdx] = group;
        return next;
      });
    },
    []
  );

  if (isDesignMode) {
    return (
      <div className="flex h-full w-full flex-col gap-3 rounded-lg border border-dashed border-gray-300 p-4">
        <div className="flex items-center gap-2">
          <Truck className="h-5 w-5 text-muted-foreground" />
          <span className="text-sm font-medium text-muted-foreground">
            {config.title || "출하계획 등록"}
          </span>
        </div>
        <div className="flex gap-2">
          {[
            "총수주잔량",
            "총출하계획량",
            "현재고",
            "가용재고",
            "생산중수량",
          ].map((label) => (
            <div
              key={label}
              className="flex flex-1 flex-col items-center rounded-lg border border-gray-200 bg-gray-50 px-3 py-2"
            >
              <span className="text-lg font-bold text-gray-400">0</span>
              <span className="text-[10px] text-gray-400">{label}</span>
            </div>
          ))}
        </div>
        <div className="flex-1 rounded-lg border border-gray-200 bg-gray-50 p-3">
          <span className="text-xs text-gray-400">상세 테이블 영역</span>
        </div>
      </div>
    );
  }

  if (loading || saving) {
    return (
      <div className="flex h-full w-full items-center justify-center">
        <div className="flex flex-col items-center gap-3">
          <Loader2 className="h-8 w-8 animate-spin text-primary" />
          <span className="text-sm text-muted-foreground">
            {saving ? "출하계획 저장 중..." : "데이터 로딩 중..."}
          </span>
        </div>
      </div>
    );
  }

  if (selectedIds.length === 0) {
    return (
      <div className="flex h-full w-full items-center justify-center">
        <span className="text-sm text-muted-foreground">
          선택된 수주가 없습니다
        </span>
      </div>
    );
  }

  const showSummary = config.showSummaryCards !== false;
  const showExisting = config.showExistingPlans !== false;

  return (
    <div className="flex h-full w-full flex-col gap-4 overflow-auto p-4">
      {itemGroups.map((group, groupIdx) => (
        <div key={group.partCode} className="flex flex-col gap-3">
          <div className="flex items-center gap-2">
            <Package className="h-4 w-4 text-primary" />
            <span className="text-sm font-semibold">
              {group.partName} ({group.partCode})
            </span>
          </div>

          {showSummary && (
            <SummaryCards
              aggregation={group.aggregation}
              visibleCards={config.visibleSummaryCards}
            />
          )}

          <DetailTable
            details={group.details}
            groupIdx={groupIdx}
            onPlanQtyChange={handlePlanQtyChange}
            showExisting={showExisting}
          />
        </div>
      ))}

    </div>
  );
};

interface VisibleCards {
  totalBalance?: boolean;
  totalPlanQty?: boolean;
  currentStock?: boolean;
  availableStock?: boolean;
  inProductionQty?: boolean;
}

const SummaryCards: React.FC<{
  aggregation: ItemAggregation;
  visibleCards?: VisibleCards;
}> = ({ aggregation, visibleCards }) => {
  const allCards = [
    {
      key: "totalBalance" as const,
      label: "총수주잔량",
      value: aggregation.totalBalance,
      icon: TrendingUp,
      color: {
        bg: "bg-blue-50",
        text: "text-blue-600",
        border: "border-blue-200",
      },
    },
    {
      key: "totalPlanQty" as const,
      label: "총출하계획량",
      value: aggregation.totalPlanQty,
      icon: Truck,
      color: {
        bg: "bg-indigo-50",
        text: "text-indigo-600",
        border: "border-indigo-200",
      },
    },
    {
      key: "currentStock" as const,
      label: "현재고",
      value: aggregation.currentStock,
      icon: Warehouse,
      color: {
        bg: "bg-emerald-50",
        text: "text-emerald-600",
        border: "border-emerald-200",
      },
    },
    {
      key: "availableStock" as const,
      label: "가용재고",
      value: aggregation.availableStock,
      icon: CheckCircle,
      color: {
        bg: aggregation.availableStock < 0 ? "bg-red-50" : "bg-amber-50",
        text:
          aggregation.availableStock < 0
            ? "text-red-600"
            : "text-amber-600",
        border:
          aggregation.availableStock < 0
            ? "border-red-200"
            : "border-amber-200",
      },
    },
    {
      key: "inProductionQty" as const,
      label: "생산중수량",
      value: aggregation.inProductionQty,
      icon: Factory,
      color: {
        bg: "bg-purple-50",
        text: "text-purple-600",
        border: "border-purple-200",
      },
    },
  ];

  const cards = allCards.filter(
    (c) => !visibleCards || visibleCards[c.key] !== false
  );

  return (
    <div className="flex gap-2">
      {cards.map((card) => {
        const Icon = card.icon;
        return (
          <div
            key={card.label}
            className={`flex flex-1 flex-col items-center rounded-lg border ${card.color.border} ${card.color.bg} px-3 py-2 transition-shadow hover:shadow-sm`}
          >
            <div className="flex items-center gap-1">
              <Icon className={`h-3.5 w-3.5 ${card.color.text}`} />
              <span className={`text-xl font-bold ${card.color.text}`}>
                {card.value.toLocaleString()}
              </span>
            </div>
            <span className={`mt-0.5 text-[10px] ${card.color.text}`}>
              {card.label}
            </span>
          </div>
        );
      })}
    </div>
  );
};

const DetailTable: React.FC<{
  details: PlanDetailRow[];
  groupIdx: number;
  onPlanQtyChange: (
    groupIdx: number,
    detailIdx: number,
    value: string
  ) => void;
  showExisting?: boolean;
}> = ({ details, groupIdx, onPlanQtyChange, showExisting = true }) => {
  const visibleDetails = details
    .map((d, idx) => ({ ...d, _origIdx: idx }))
    .filter((d) => showExisting || d.type === "new");
  return (
    <div className="overflow-hidden rounded-lg border">
      <table className="w-full text-sm">
        <thead>
          <tr className="border-b bg-muted/50">
            <th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground">
              구분
            </th>
            <th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground">
              수주번호
            </th>
            <th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground">
              거래처
            </th>
            <th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground">
              납기일
            </th>
            <th className="px-3 py-2 text-right text-xs font-medium text-muted-foreground">
              미출하
            </th>
            <th className="px-3 py-2 text-right text-xs font-medium text-muted-foreground">
              출하계획량
            </th>
          </tr>
        </thead>
        <tbody>
          {visibleDetails.map((detail, detailIdx) => (
            <tr
              key={`${detail.type}-${detail.sourceId}-${detail.existingPlanId || detailIdx}`}
              className="border-b last:border-b-0 hover:bg-muted/30"
            >
              <td className="px-3 py-2">
                {detail.type === "existing" ? (
                  <Badge variant="secondary" className="text-[10px]">
                    기존
                  </Badge>
                ) : (
                  <Badge className="bg-primary text-[10px] text-primary-foreground">
                    신규
                  </Badge>
                )}
              </td>
              <td className="px-3 py-2 text-xs">{detail.orderNo}</td>
              <td className="px-3 py-2 text-xs">{detail.partnerName}</td>
              <td className="px-3 py-2 text-xs">
                {detail.dueDate || "-"}
              </td>
              <td className="px-3 py-2 text-right text-xs font-medium">
                {detail.balanceQty.toLocaleString()}
              </td>
              <td className="px-3 py-2 text-right">
                {detail.type === "existing" ? (
                  <span className="text-xs text-muted-foreground">
                    {detail.planQty.toLocaleString()}
                  </span>
                ) : (
                  <Input
                    type="number"
                    min={0}
                    max={
                      detail.balanceQty > 0 ? detail.balanceQty : undefined
                    }
                    value={detail.planQty || ""}
                    onChange={(e) =>
                      onPlanQtyChange(groupIdx, detail._origIdx, e.target.value)
                    }
                    className="ml-auto h-7 w-24 text-right text-xs"
                    placeholder="0"
                  />
                )}
              </td>
            </tr>
          ))}
          {visibleDetails.length === 0 && (
            <tr>
              <td
                colSpan={6}
                className="px-3 py-6 text-center text-xs text-muted-foreground"
              >
                데이터가 없습니다
              </td>
            </tr>
          )}
        </tbody>
      </table>
    </div>
  );
};

export const ShippingPlanEditorWrapper: React.FC<
  ShippingPlanEditorComponentProps
> = (props) => {
  return <ShippingPlanEditorComponent {...props} />;
};
