'use client';

/**
 * PopupTemplateRenderer — form-popup 전용 템플릿 렌더러.
 *
 * TemplateRenderer(대시보드 카드용, 반응형 line-grid)와 완전히 분리된 경로.
 * 팝업은 스튜디오에서 지정한 canvas(예: 837×632) 치수를 1:1 로 유지해야 하고
 * 반응형 재배치가 필요 없기 때문에 자체 absolute 좌표 파이프라인을 사용한다.
 *
 * 창 크기와 canvas 가 다른 경우의 전략:
 *   1) 팝업 부모는 `window.open` 에서 대략적인 크기로 열리고
 *      (브라우저가 그 값을 무시할 수도 있음)
 *   2) 이 컴포넌트가 자체 컨테이너 크기(뷰포트)를 측정해서
 *      canvas 를 `transform: scale(fit)` 로 뷰포트에 꽉 채운다
 *   3) 결과: 창 크기 = canvas × scale 로 빈 공간/잘림 없이 표시
 *
 * 공유: ensureV2Views(뷰 정규화) / BlockRenderer(컴포넌트 렌더) 만 재사용.
 * 그 외 canvas 좌표 계산/스케일/레이아웃은 이 파일 내부에서 완결.
 */

import {
  useEffect,
  useLayoutEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import type {
  BlockV2,
  CanvasV2,
  Template,
} from '@/types/invyone-component';
import { ensureV2Views } from '@/lib/utils/templateMigrate';
import { BlockRenderer } from './BlockRenderer';
import type {
  TemplateRenderContext,
  ViewKey,
} from './TemplateRenderer';

interface PopupTemplateRendererProps {
  template: Template | any;
  context: TemplateRenderContext;
  /** 'create' | 'edit' — 팝업은 list 뷰가 의미 없음 */
  view: Exclude<ViewKey, 'list'>;
}

export function PopupTemplateRenderer({
  template,
  context,
  view,
}: PopupTemplateRendererProps) {
  // template.views 는 object 일수도, DB 에서 문자열로 넘어올 수도 있다.
  // 1차로 파싱 보정.
  const rawViews = useMemo(() => {
    const v = template?.views ?? (template as any)?.VIEWS;
    if (!v) return {} as Record<string, any>;
    if (typeof v === 'string') {
      try {
        return JSON.parse(v) as Record<string, any>;
      } catch {
        return {} as Record<string, any>;
      }
    }
    return v as Record<string, any>;
  }, [template]);

  const v2Views = useMemo(() => ensureV2Views(rawViews), [rawViews]);
  const currentView = view === 'create' ? v2Views.create : v2Views.edit;
  const blocks: BlockV2[] = currentView?.blocks ?? [];

  // canvas 는 ensureV2Views 에만 의존하지 않고 원본 views 에서 직접 찾는다.
  // saveTemplate 은 뷰별 해상도를 `screenResolutions[view]` 로 저장한다.
  const canvas: CanvasV2 = useMemo(() => {
    const sr =
      rawViews?.viewCanvases?.[view] ??
      rawViews?.screenResolutions?.[view] ??
      rawViews?.screen_resolutions?.[view] ??
      rawViews?.screenResolution ??
      rawViews?.screen_resolution ??
      null;
    const w = Number(sr?.width ?? sr?.baseWidth);
    const h = Number(sr?.height ?? sr?.baseHeight);
    if (isFinite(w) && isFinite(h) && w > 0 && h > 0) {
      return { baseWidth: w, baseHeight: h, aspectPolicy: 'preserve' };
    }
    // ensureV2Views 가 만들어둔 canvas 가 있으면 그것, 아니면 최종 폴백.
    return (
      (v2Views?.viewCanvases as any)?.[view] ??
      v2Views?.canvas ?? {
        baseWidth: 1920,
        baseHeight: 1080,
        aspectPolicy: 'preserve',
      }
    );
  }, [rawViews, v2Views, view]);

  // 뷰포트 크기 실측 — 부모 DOM 이 아닌 window 기준으로 측정해서
  // flex/overflow 레이아웃 타이밍 이슈를 피한다. 첫 렌더에도 바로 실제 값이
  // 들어가도록 lazy init(window 기반).
  const [viewport, setViewport] = useState<{ w: number; h: number }>(() => {
    if (typeof window === 'undefined') return { w: 1920, h: 1080 };
    return { w: window.innerWidth, h: window.innerHeight };
  });
  useLayoutEffect(() => {
    if (typeof window === 'undefined') return;
    const update = () =>
      setViewport({ w: window.innerWidth, h: window.innerHeight });
    update();
    window.addEventListener('resize', update);
    return () => window.removeEventListener('resize', update);
  }, []);

  // 팝업 창이 너무 크게 열린 경우 한 번 줄여보기 (resizeTo). 차단돼도 무관 —
  // scale fit 이 받아낸다.
  const didResizeRef = useRef(false);
  useEffect(() => {
    if (didResizeRef.current) return;
    if (typeof window === 'undefined') return;
    try {
      const needInnerW = canvas.baseWidth + 16;
      const needInnerH = canvas.baseHeight + 8;
      const chromeW = Math.max(0, window.outerWidth - window.innerWidth);
      const chromeH = Math.max(0, window.outerHeight - window.innerHeight);
      const targetOuterW = needInnerW + chromeW;
      const targetOuterH = needInnerH + chromeH;
      if (
        Math.abs(targetOuterW - window.outerWidth) > 8 ||
        Math.abs(targetOuterH - window.outerHeight) > 8
      ) {
        window.resizeTo(targetOuterW, targetOuterH);
      }
    } catch {
      /* 브라우저가 resizeTo 차단 — 무시. scale 이 보정 */
    }
    didResizeRef.current = true;
  }, [canvas.baseWidth, canvas.baseHeight]);

  if (!blocks.length) {
    return (
      <div className="flex h-full w-full flex-col items-center justify-center gap-2 py-8 text-center">
        <div className="text-4xl opacity-40">📋</div>
        <div className="text-sm font-medium text-slate-600 dark:text-slate-300">
          이 뷰가 비어있습니다
        </div>
      </div>
    );
  }

  // scale 계산 — viewport 대비 canvas 가 들어가는 최대 비율. 1 이상이면 확대,
  // 1 이하면 축소. 어느 쪽이든 canvas 가 창을 꽉 채운다.
  const scale = useMemo(() => {
    // form-popup 페이지 상단 헤더(약 44px) 만 빼고 나머지를 canvas 영역으로 사용.
    const availW = viewport.w;
    const availH = Math.max(1, viewport.h - 44);
    const sx = availW / canvas.baseWidth;
    const sy = availH / canvas.baseHeight;
    const s = Math.min(sx, sy);
    const final = Number.isFinite(s) && s > 0 ? s : 1;
    if (typeof window !== 'undefined') {
      /* eslint-disable no-console */
      console.log('[PopupTemplateRenderer]', {
        viewportW: viewport.w,
        viewportH: viewport.h,
        canvasW: canvas.baseWidth,
        canvasH: canvas.baseHeight,
        sx,
        sy,
        scale: final,
      });
      /* eslint-enable no-console */
    }
    return final;
  }, [viewport, canvas.baseWidth, canvas.baseHeight]);

  const displayW = canvas.baseWidth * scale;
  const displayH = canvas.baseHeight * scale;

  return (
    <div
      style={{
        width: '100%',
        height: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        overflow: 'hidden',
      }}
    >
      <div
        style={{
          position: 'relative',
          width: `${displayW}px`,
          height: `${displayH}px`,
          flexShrink: 0,
          overflow: 'hidden',
        }}
      >
        <div
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            width: `${canvas.baseWidth}px`,
            height: `${canvas.baseHeight}px`,
            transform: `scale(${scale})`,
            transformOrigin: 'top left',
          }}
        >
          {blocks.map((block) => (
            <div
              key={block.id}
              className={`ppl-slot role-${block.role} policy-${block.responsivePolicy}`}
              data-comp={block.componentId}
              style={{
                position: 'absolute',
                left: `${block.xPct * canvas.baseWidth}px`,
                top: `${block.yPct * canvas.baseHeight}px`,
                width: `${block.wPct * canvas.baseWidth}px`,
                height: `${block.hPct * canvas.baseHeight}px`,
                boxSizing: 'border-box',
              }}
            >
              <BlockRenderer
                block={block}
                context={context}
                view={view}
                canvas={canvas}
              />
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}
