'use client';

import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { createPortal } from 'react-dom';
import { RefreshCw, X, Settings, Maximize2, Minimize2 } from 'lucide-react';
import { toast } from 'sonner';
import { getTemplateInfo } from '@/lib/api/template';
import { fcList, fcDelete } from '@/lib/api/fcData';
import type { FieldConfig, Template } from '@/types/invyone-component';
import { TemplateRenderer, type TemplateRenderContext } from './TemplateRenderer';

/**
 * 뷰별 팝업 크기 계산 — 빌더(ScreenDesigner)가 저장한
 * template.views.screenResolutions.{create|edit} 를 우선 사용.
 * 없으면 공통 screenResolution, 그것도 없으면 900×700 폴백.
 */
function computePopupFeatures(
  template: Template | null,
  view: 'create' | 'edit',
): string {
  const viewsObj = (template?.views as any) ?? {};
  const res =
    viewsObj?.screenResolutions?.[view] ??
    viewsObj?.screen_resolutions?.[view] ??
    viewsObj?.screenResolution ??
    viewsObj?.screen_resolution;
  const canvasW = Math.max(400, Math.round(Number(res?.width) || 900));
  const canvasH = Math.max(400, Math.round(Number(res?.height) || 700));
  // 팝업 창 width/height 는 outer(브라우저 크롬 포함). form-popup 페이지는
  //   - 상단 헤더(타이틀 바): ~44px
  //   - 내용 영역 padding: 좌우 0(제거됨), 상하 0
  //   - 브라우저 top chrome(탭+주소창): ~90px
  //   - 좌우 스크롤바/여유: ~32px
  // canvas 에 딱 맞게 열어서 가로 스크롤 방지. 부족분은 팝업 페이지에서
  // resizeTo 로 실측 보정.
  const chromeW = 32; /* 브라우저 좌우 border + scrollbar 여유 */
  const chromeH = 44 /* 헤더 */ + 90 /* 브라우저 top chrome */ + 16; /* 여유 */
  const outerW = canvasW + chromeW;
  const outerH = canvasH + chromeH;
  return `width=${outerW},height=${outerH},resizable=yes,scrollbars=yes`;
}

/** 팝업 고유 key + opener name — 여러 팝업 동시 허용 */
function newPopupKey(): string {
  return `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
}

interface DashboardCardProps {
  card: Record<string, any>;
  editMode: boolean;
  onRemove: (cardId: string) => void;
  onOpenSettings?: (cardId: string) => void;
}

export function DashboardCard({
  card,
  editMode,
  onRemove,
  onOpenSettings,
}: DashboardCardProps) {
  const cardId = card.card_id ?? card.CARD_ID;
  const templateId = card.template_id ?? card.TEMPLATE_ID;
  const templateName = card.template_name ?? card.TEMPLATE_NAME ?? '템플릿';
  const templateCategory = card.template_category ?? card.TEMPLATE_CATEGORY ?? '';
  const primaryTable = card.primary_table ?? card.PRIMARY_TABLE ?? '';

  /** 전체화면 — 일시 상태(DB 저장 X). ESC 또는 같은 버튼 재클릭으로 해제.
   *  closing flag 로 exit 애니메이션 후 unmount (CSS 의 dash-card-fs-out keyframe). */
  const [isFullscreen, setIsFullscreen] = useState(false);
  const [closing, setClosing] = useState(false);

  const exitFullscreen = useCallback(() => {
    setClosing(true);
    window.setTimeout(() => {
      setIsFullscreen(false);
      setClosing(false);
    }, 220);
  }, []);

  const toggleFullscreen = useCallback(() => {
    if (isFullscreen) {
      if (!closing) exitFullscreen();
    } else {
      setIsFullscreen(true);
    }
  }, [isFullscreen, closing, exitFullscreen]);

  useEffect(() => {
    if (!isFullscreen) return;
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') exitFullscreen();
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [isFullscreen, exitFullscreen]);

  const [fields, setFields] = useState<FieldConfig[]>([]);
  const [template, setTemplate] = useState<Template | null>(null);
  const [templateLoaded, setTemplateLoaded] = useState(false);
  const [loadError, setLoadError] = useState<string | null>(null);

  const [data, setData] = useState<Record<string, any>[]>([]);
  const [totalCount, setTotalCount] = useState(0);
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState(20);
  const [searchParams, setSearchParams] = useState<Record<string, any>>({});
  const [loading, setLoading] = useState(false);
  const [selectedRow, setSelectedRow] = useState<Record<string, any> | null>(null);

  const mountedRef = useRef(true);
  /** 이 카드가 연 팝업의 key 집합 — 저장 알림이 자기 카드에서 온 건지 구분용 */
  const popupKeysRef = useRef<Set<string>>(new Set());

  // Template + fields 로드
  useEffect(() => {
    mountedRef.current = true;
    if (!primaryTable && !templateId) {
      setTemplateLoaded(true);
      return;
    }
    const load = async () => {
      setLoadError(null);
      try {
        let resolvedFields: FieldConfig[] = [];
        if (templateId) {
          const tpl = await getTemplateInfo(templateId);
          if (tpl && mountedRef.current) {
            setTemplate(tpl as Template);
            if (Array.isArray(tpl.fields)) resolvedFields = tpl.fields as FieldConfig[];
          }
        }
        // ★ DB meta 자동 fallback 제거 (하드코딩 방지).
        // Template.fields 가 비어있으면 fields 도 빈 채로 둔다 — 빌더에서
        // 사용자가 명시적으로 선택한 필드만 반영. 스키마 덤프 금지.
        if (mountedRef.current) {
          setFields(resolvedFields);
          setTemplateLoaded(true);
        }
      } catch (err: any) {
        console.error('[DashboardCard] Template 로드 실패:', err);
        if (mountedRef.current) {
          setLoadError(err?.message ?? '템플릿 로드 실패');
          setTemplateLoaded(true);
        }
      }
    };
    load();
    return () => {
      mountedRef.current = false;
    };
  }, [primaryTable, templateId]);

  // 데이터 조회
  const loadData = useCallback(async () => {
    if (!primaryTable || !templateLoaded) return;
    setLoading(true);
    try {
      const result = await fcList({
        tableName: primaryTable,
        page,
        size: pageSize,
        ...searchParams,
      });
      if (mountedRef.current) {
        setData(result?.data ?? result?.list ?? []);
        setTotalCount(result?.total ?? result?.total_count ?? 0);
      }
    } catch (err) {
      console.error('[DashboardCard] 데이터 조회 실패:', err);
    } finally {
      if (mountedRef.current) setLoading(false);
    }
  }, [primaryTable, templateLoaded, page, pageSize, searchParams]);

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

  // 검색/페이지/선택
  const handleSearch = useCallback((params: Record<string, any>) => {
    setSearchParams(params);
    setPage(1);
  }, []);

  const handlePageChange = useCallback(({ page: p, size }: { page: number; size: number }) => {
    setPage(p);
    setPageSize(size);
  }, []);

  const handleRowSelect = useCallback((row: Record<string, any>) => {
    setSelectedRow(row);
  }, []);

  // PK 컬럼 (첫 pk 필드)
  const pkColumn = useMemo(() => {
    const pkField = fields.find((f) => f.pk);
    return pkField?.column ?? '';
  }, [fields]);

  /** 공통 — 팝업 창 열기. 뷰별 해상도 + 초기 데이터 localStorage 시드 + 고유 key */
  const openFormPopup = useCallback(
    (mode: 'create' | 'edit', initialRow: Record<string, any>) => {
      if (!templateId) {
        toast.error('templateId 가 없습니다');
        return;
      }
      if (!primaryTable) {
        toast.error('primary_table 이 설정되어 있지 않습니다');
        return;
      }
      const key = newPopupKey();
      try {
        // Optimistic seed — 부모가 들고 있는 template 을 넘겨서 팝업이 로딩
        // 플래시 없이 즉시 렌더하게 한다. 팝업은 이걸로 즉시 렌더 후
        // 백그라운드에서 getTemplateInfo 로 재검증해서 stale 이면 교체.
        localStorage.setItem(
          `form-popup:${key}`,
          JSON.stringify({
            initialRow,
            primaryTable,
            templateName,
            template,
            fetchedAt: Date.now(),
          }),
        );
      } catch {
        /* storage 실패해도 팝업은 열어줌 — 팝업 쪽에서 API 로 fetch */
      }
      popupKeysRef.current.add(key);
      const url = `/form-popup?templateId=${encodeURIComponent(
        String(templateId),
      )}&mode=${mode}&key=${encodeURIComponent(key)}`;
      const features = computePopupFeatures(template, mode);
      const win = window.open(url, `popup-${key}`, features);
      if (!win) {
        toast.error('팝업이 차단되었습니다. 브라우저 팝업 허용을 확인하세요.');
        popupKeysRef.current.delete(key);
        try {
          localStorage.removeItem(`form-popup:${key}`);
        } catch {
          /* ignore */
        }
      }
    },
    [templateId, primaryTable, templateName, template],
  );

  // CRUD 액션
  const handleAdd = useCallback(() => {
    const defaults: Record<string, any> = {};
    for (const f of fields) {
      if (f.defaultValue !== undefined) defaults[f.column] = f.defaultValue;
    }
    openFormPopup('create', defaults);
  }, [fields, openFormPopup]);

  const handleEdit = useCallback(() => {
    if (!selectedRow) {
      toast.warning('수정할 행을 선택하세요');
      return;
    }
    openFormPopup('edit', { ...selectedRow });
  }, [selectedRow, openFormPopup]);

  const handleDelete = useCallback(async () => {
    if (!selectedRow) {
      toast.warning('삭제할 행을 선택하세요');
      return;
    }
    if (!pkColumn) {
      toast.error('PK 컬럼이 없어 삭제할 수 없습니다');
      return;
    }
    if (!confirm('정말 삭제하시겠습니까?')) return;
    try {
      const id = String(selectedRow[pkColumn] ?? '');
      if (!id) throw new Error('PK 값이 비어있습니다');
      await fcDelete(primaryTable, [id]);
      setSelectedRow(null);
      await loadData();
      toast.success('삭제되었습니다');
    } catch (err: any) {
      console.error('[DashboardCard] 삭제 실패:', err);
      toast.error(err?.message ?? '삭제 실패');
    }
  }, [selectedRow, pkColumn, primaryTable, loadData]);

  /** 팝업 창에서 저장 성공 알림 받으면 리로드 */
  useEffect(() => {
    const handler = (ev: MessageEvent) => {
      if (ev.origin !== window.location.origin) return;
      const data = ev.data;
      if (!data || data.type !== 'form-popup-saved') return;
      const key = String(data.key ?? '');
      if (!popupKeysRef.current.has(key)) return; // 다른 카드의 팝업이면 무시
      popupKeysRef.current.delete(key);
      loadData();
      toast.success(data.mode === 'edit' ? '수정되었습니다' : '등록되었습니다');
    };
    window.addEventListener('message', handler);
    return () => window.removeEventListener('message', handler);
  }, [loadData]);

  // TemplateRenderer 로 전달할 공유 context — 목록 뷰 전용.
  // 등록/수정 폼 바인딩은 별도 팝업 창(/form-popup)이 독립 관리.
  const renderContext: TemplateRenderContext = useMemo(
    () => ({
      fields,
      data,
      loading,
      primaryTable,
      selectedRow,
      totalCount,
      page,
      pageSize,
      searchParams,
      onSearch: handleSearch,
      onRowSelect: handleRowSelect,
      onPageChange: handlePageChange,
      onAdd: handleAdd,
      onEdit: handleEdit,
      onDelete: handleDelete,
    }),
    [
      fields,
      data,
      loading,
      primaryTable,
      selectedRow,
      totalCount,
      page,
      pageSize,
      searchParams,
      handleSearch,
      handleRowSelect,
      handlePageChange,
      handleAdd,
      handleEdit,
      handleDelete,
    ],
  );

  const cardElement = (
    <div className={`dash-card${isFullscreen ? ' fullscreen' : ''}${closing ? ' closing' : ''}`}>
      <div className="dash-card-head">
        <div className="dash-card-head-l">
          <div className="dash-card-icon">📋</div>
          <div className="dash-card-title">{templateName}</div>
          {templateCategory && <div className="dash-card-bdg">{templateCategory}</div>}
        </div>
        <div className="dash-card-head-r">
          <button
            className="dash-card-btn"
            title="새로고침"
            onClick={(e) => {
              e.stopPropagation();
              loadData();
            }}
          >
            <RefreshCw size={13} />
          </button>
          {onOpenSettings && (
            <button
              className="dash-card-btn"
              title="설정"
              onClick={(e) => {
                e.stopPropagation();
                onOpenSettings(cardId);
              }}
            >
              <Settings size={13} />
            </button>
          )}
          <button
            className="dash-card-btn"
            title={isFullscreen ? '원래 크기로 (ESC)' : '전체화면'}
            onClick={(e) => {
              e.stopPropagation();
              toggleFullscreen();
            }}
          >
            {isFullscreen ? <Minimize2 size={13} /> : <Maximize2 size={13} />}
          </button>
          {editMode && (
            <button
              className="dash-card-btn danger"
              title="카드 삭제"
              onClick={(e) => {
                e.stopPropagation();
                onRemove(cardId);
              }}
            >
              <X size={13} />
            </button>
          )}
        </div>
      </div>

      <div
        className="dash-card-body"
        style={{
          containerType: 'inline-size',
          containerName: 'card',
        }}
      >
        {loadError ? (
          <div className="dash-card-error">⚠ {loadError}</div>
        ) : !templateLoaded ? (
          <div className="dash-card-loading">템플릿 로딩 중...</div>
        ) : !template ? (
          <div className="dash-card-error">템플릿을 찾을 수 없습니다</div>
        ) : (
          <TemplateRenderer template={template} context={renderContext} />
        )}
      </div>

      {/* 8방향 리사이즈 핸들 — edit mode 에서만 보임 (CSS 제어) */}
      <div className="dash-resize-handle n" data-resize="n" />
      <div className="dash-resize-handle s" data-resize="s" />
      <div className="dash-resize-handle e" data-resize="e" />
      <div className="dash-resize-handle w" data-resize="w" />
      <div className="dash-resize-handle ne" data-resize="ne" />
      <div className="dash-resize-handle nw" data-resize="nw" />
      <div className="dash-resize-handle se" data-resize="se" />
      <div className="dash-resize-handle sw" data-resize="sw" />
    </div>
  );

  // 부모 .v5-body 가 overflow:hidden 으로 stacking context 를 만들어
  // position:fixed 가 viewport 가 아닌 .v5-body 기준으로 갇힘.
  // fullscreen 시에는 document.body 에 Portal 로 마운트해서 viewport 기준 보장.
  if (isFullscreen && typeof document !== 'undefined') {
    return createPortal(cardElement, document.body);
  }
  return cardElement;
}
