<template>
  <div class="editor-canvas-frame">
    <div v-if="baseUrl" class="editor-canvas-frame__viewport" :class="viewportClass">
      <iframe
        ref="frameRef"
        class="editor-canvas-frame__iframe"
        :src="baseUrl"
        title="editor-canvas"
        loading="lazy"
        @load="handleFrameLoad"
      />
      <div
        class="editor-canvas-frame__status-pill"
        :class="`editor-canvas-frame__status-pill--${canvasStatusTag.type}`"
      >
        <span class="editor-canvas-frame__status-dot" />
        {{ canvasStatusTag.label }}
      </div>
    </div>

    <div v-else class="editor-canvas-frame__empty">
      <p class="editor-canvas-frame__empty-title">先填入要編輯的頁面網址</p>
      <p class="editor-canvas-frame__empty-body">
        畫布會直接載入目標頁面，之後所有可視化操作都會從這裡發生。
      </p>
    </div>
  </div>
</template>

<script setup>
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"
import {
  createStatusSummaryMessage,
  createFocusSelectorMessage,
  createInspectSelectorMessage,
  createStartInlineEditMessage,
  createMoveBlockMessage,
  createToggleBlockVisibilityMessage,
  createDuplicateBlockMessage,
  createDeleteBlockMessage,
  createInsertBlockMessage,
  createRestoreCanvasStateMessage,
  createPreviewOperationsMessage,
  editorBridgeEventType,
  normalizeCanvasSelectionPayload,
} from "@/module/editor/model/editor-bridge-protocol"

const props = defineProps({
  baseUrl: {
    type: String,
    default: "",
  },
  deviceMode: {
    type: String,
    default: "desktop",
  },
  candidates: {
    type: Array,
    default: () => [],
  },
  selectedSelector: {
    type: String,
    default: "",
  },
  previewStatus: {
    type: Object,
    default: () => ({
      title: "",
      status: "idle",
    }),
  },
  previewOperations: {
    type: Array,
    default: () => [],
  },
  feedbackSummary: {
    type: Object,
    default: () => ({
      title: "",
      selectorLabel: "",
      detail: "",
      helper: "",
      status: "info",
    }),
  },
  bridgeCommand: {
    type: Object,
    default: null,
  },
})

const emit = defineEmits([
  "select-candidate",
  "hover-candidate",
  "hover-clear",
  "hotspot-action",
  "inline-text-change",
  "inline-attribute-change",
  "inline-style-change",
  "canvas-ready",
  "bridge-outbound",
])

const frameRef = ref(null)
const canvasState = ref("idle")
const canvasOrigin = ref("")
const lastHoverSelector = ref("")
const lastIncomingSelector = ref("")
const lastFocusedSelector = ref("")
const lastOutboundCommand = ref("")
const viewportClass = computed(
  () => `editor-canvas-frame__viewport--${props.deviceMode || "desktop"}`
)

const canvasStatusTag = computed(() => {
  switch (canvasState.value) {
    case "connected":
      return {
        type: "success",
        label: "已連線",
      }
    case "loaded":
      return {
        type: "info",
        label: "頁面已載入",
      }
    default:
      return {
        type: "warning",
        label: props.baseUrl ? "等待編輯橋接" : "尚未啟動",
      }
  }
})

const handleFrameLoad = () => {
  canvasState.value = "loaded"
  canvasOrigin.value = ""
  pushSelectedSelectorToCanvas()
}

const postBridgeMessage = (message, meta = {}) => {
  if (!frameRef.value?.contentWindow || !message?.type) {
    return
  }

  if (
    [
      editorBridgeEventType.FOCUS_SELECTOR,
      editorBridgeEventType.INSPECT_SELECTOR,
      editorBridgeEventType.START_INLINE_EDIT,
      editorBridgeEventType.MOVE_BLOCK,
      editorBridgeEventType.TOGGLE_BLOCK_VISIBILITY,
      editorBridgeEventType.DUPLICATE_BLOCK,
      editorBridgeEventType.DELETE_BLOCK,
      editorBridgeEventType.INSERT_BLOCK,
    ].includes(message.type) &&
    !message?.selector
  ) {
    return
  }

  frameRef.value.contentWindow.postMessage(message, canvasOrigin.value || "*")
  if (message.selector) {
    lastFocusedSelector.value = message.selector
  }
  lastOutboundCommand.value = meta.label || message.type
  emit("bridge-outbound", {
    type: meta.logType || message.type,
    value: message.selector,
    source: meta.source || "editor-workspace",
  })
}

const pushSelectedSelectorToCanvas = () => {
  if (!props.selectedSelector || !frameRef.value?.contentWindow) {
    return
  }

  postBridgeMessage(
    createFocusSelectorMessage({
      selector: props.selectedSelector,
    }),
    {
      label: "已同步焦點到畫布",
      logType: "focus-selector",
      source: "editor-workspace",
    }
  )
}

const runBridgeCommand = (command) => {
  if (!command?.type) {
    return
  }

  if (
    command.type !== editorBridgeEventType.RESTORE_CANVAS_STATE &&
    !command?.selector
  ) {
    return
  }

  if (command.type === editorBridgeEventType.INSPECT_SELECTOR) {
    postBridgeMessage(
      createInspectSelectorMessage({
        selector: command.selector,
        source: command.source,
      }),
      {
        label: "已要求畫布檢查區塊",
        logType: "inspect-selector",
        source: command.source || "editor-workspace",
      }
    )
    return
  }

  if (command.type === editorBridgeEventType.START_INLINE_EDIT) {
    postBridgeMessage(
      createStartInlineEditMessage({
        selector: command.selector,
        editKind: command.editKind,
        attributeName: command.attributeName,
        attributeValue: command.attributeValue,
        styleProperty: command.styleProperty,
        styleValue: command.styleValue,
        source: command.source,
      }),
      {
        label: "已要求畫布進入頁內文字編輯",
        logType: "start-inline-edit",
        source: command.source || "editor-workspace",
      }
    )
    return
  }

  if (command.type === editorBridgeEventType.MOVE_BLOCK) {
    postBridgeMessage(
      createMoveBlockMessage({
        selector: command.selector,
        direction: command.direction,
        source: command.source,
      }),
      {
        label: command.direction === "up" ? "已要求區塊上移" : "已要求區塊下移",
        logType: "move-block",
        source: command.source || "editor-workspace",
      }
    )
    return
  }

  if (command.type === editorBridgeEventType.TOGGLE_BLOCK_VISIBILITY) {
    postBridgeMessage(
      createToggleBlockVisibilityMessage({
        selector: command.selector,
        source: command.source,
      }),
      {
        label: "已切換區塊顯示狀態",
        logType: "toggle-block-visibility",
        source: command.source || "editor-workspace",
      }
    )
    return
  }

  if (command.type === editorBridgeEventType.DUPLICATE_BLOCK) {
    postBridgeMessage(
      createDuplicateBlockMessage({
        selector: command.selector,
        source: command.source,
      }),
      {
        label: "已要求複製區塊",
        logType: "duplicate-block",
        source: command.source || "editor-workspace",
      }
    )
    return
  }

  if (command.type === editorBridgeEventType.DELETE_BLOCK) {
    postBridgeMessage(
      createDeleteBlockMessage({
        selector: command.selector,
        source: command.source,
      }),
      {
        label: "已要求刪除區塊",
        logType: "delete-block",
        source: command.source || "editor-workspace",
      }
    )
    return
  }

  if (command.type === editorBridgeEventType.INSERT_BLOCK) {
    postBridgeMessage(
      createInsertBlockMessage({
        selector: command.selector,
        position: command.position,
        blockType: command.blockType,
        source: command.source,
      }),
      {
        label:
          command.position === "before"
            ? `已要求前面插入${command.blockTypeLabel || "區塊"}`
            : `已要求後面插入${command.blockTypeLabel || "區塊"}`,
        logType: "insert-block",
        source: command.source || "editor-workspace",
      }
    )
    return
  }

  if (command.type === editorBridgeEventType.RESTORE_CANVAS_STATE) {
    postBridgeMessage(
      createRestoreCanvasStateMessage({
        pageHtml: command.pageHtml,
        selector: command.selector,
        source: command.source,
      }),
      {
        label: "已還原畫布狀態",
        logType: "restore-canvas-state",
        source: command.source || "editor-workspace",
      }
    )
    return
  }

  postBridgeMessage(
    createFocusSelectorMessage({
      selector: command.selector,
      source: command.source,
    }),
    {
      label: "已同步焦點到畫布",
      logType: "focus-selector",
      source: command.source || "editor-workspace",
    }
  )
}

const pushFeedbackSummaryToCanvas = () => {
  if (!frameRef.value?.contentWindow || !props.feedbackSummary?.title) {
    return
  }

  postBridgeMessage(
    createStatusSummaryMessage({
      mode: props.feedbackSummary.mode,
      modeLabel: props.feedbackSummary.modeLabel,
      status: props.feedbackSummary.status,
      title: props.feedbackSummary.title,
      selector: props.feedbackSummary.selectorLabel,
      detail: props.feedbackSummary.detail,
      helper: props.feedbackSummary.helper,
      primaryActionLabel: props.feedbackSummary.primaryActionLabel,
      secondaryActionLabel: props.feedbackSummary.secondaryActionLabel,
    }),
    {
      label: "已同步畫布回饋摘要",
      logType: "status-summary",
      source: "editor-workspace",
    }
  )
}

const pushPreviewOperationsToCanvas = () => {
  if (!frameRef.value?.contentWindow) {
    return
  }

  postBridgeMessage(
    createPreviewOperationsMessage({
      operations: props.previewOperations,
    }),
    {
      label: "已同步預覽結果到畫布",
      logType: "preview-operations",
      source: "editor-workspace",
    }
  )
}

const handleMessage = (event) => {
  if (!props.baseUrl || !frameRef.value?.contentWindow || event.source !== frameRef.value.contentWindow) {
    return
  }

  const payload = event.data || {}

  if (payload?.type === editorBridgeEventType.READY) {
    canvasState.value = "connected"
    canvasOrigin.value = event.origin || ""
    emit("canvas-ready", payload)
    pushPreviewOperationsToCanvas()
    return
  }

  if (payload?.type === editorBridgeEventType.HOVER && payload.selector) {
    const normalizedPayload = normalizeCanvasSelectionPayload(payload)
    canvasState.value = "connected"
    lastHoverSelector.value = normalizedPayload.selector
    emit("hover-candidate", normalizedPayload)
    return
  }

  if (payload?.type === editorBridgeEventType.HOVER_CLEAR) {
    lastHoverSelector.value = ""
    emit("hover-clear")
    return
  }

  if (payload?.type === editorBridgeEventType.HOTSPOT_ACTION) {
    emit("hotspot-action", {
      action: payload.action || "",
      selector: payload.selector || "",
      tag: payload.tag || "",
      text: payload.text || "",
      href: payload.href || "",
      src: payload.src || "",
      intentChangeType: payload.intent_change_type || "",
      intentField: payload.intent_field || "",
      intentAttributeName: payload.intent_attribute_name || "",
      intentAttributeValue: payload.intent_attribute_value || "",
      source: payload.source || "canvas-hotspot",
    })
    emit("bridge-outbound", {
      type: payload.action || payload.type,
      value: payload.selector || "",
      source: payload.source || "canvas-hotspot",
    })
    return
  }

  if (payload?.type === editorBridgeEventType.INLINE_TEXT_CHANGE && payload.selector) {
    emit("inline-text-change", {
      selector: payload.selector || "",
      text: payload.text || "",
      pageHtml: payload.page_html || "",
      source: payload.source || "canvas-inline-edit",
    })
    emit("bridge-outbound", {
      type: payload.type,
      value: payload.selector || "",
      source: payload.source || "canvas-inline-edit",
    })
    return
  }

  if (payload?.type === editorBridgeEventType.INLINE_ATTRIBUTE_CHANGE && payload.selector) {
    emit("inline-attribute-change", {
      selector: payload.selector || "",
      attributeName: payload.attribute_name || "",
      attributeValue: payload.attribute_value || "",
      pageHtml: payload.page_html || "",
      source: payload.source || "canvas-inline-edit",
    })
    emit("bridge-outbound", {
      type: payload.type,
      value: payload.selector || "",
      source: payload.source || "canvas-inline-edit",
    })
    return
  }

  if (payload?.type === editorBridgeEventType.INLINE_STYLE_CHANGE && payload.selector) {
    emit("inline-style-change", {
      selector: payload.selector || "",
      styleProperty: payload.style_property || "",
      styleValue: payload.style_value || "",
      pageHtml: payload.page_html || "",
      source: payload.source || "canvas-inline-edit",
    })
    emit("bridge-outbound", {
      type: payload.type,
      value: payload.selector || "",
      source: payload.source || "canvas-inline-edit",
    })
    return
  }

  if (payload?.type === editorBridgeEventType.BLOCK_VISIBILITY_CHANGE && payload.selector) {
    emit("bridge-outbound", {
      type: payload.type,
      value: payload.selector || "",
      source: payload.source || "canvas-bridge",
      hidden: Boolean(payload.hidden),
      pageHtml: payload.page_html || "",
    })
    emit("select-candidate", normalizeCanvasSelectionPayload(payload))
    return
  }

  if (payload?.type === editorBridgeEventType.BLOCK_STRUCTURE_CHANGE) {
    emit("bridge-outbound", {
      type: payload.type,
      value: payload.selector || "",
      source: payload.source || "canvas-bridge",
      action: payload.action || "",
      nextSelector: payload.next_selector || "",
      blockType: payload.block_type || "",
      tag: payload.tag || "",
      text: payload.text || "",
      href: payload.href || "",
      src: payload.src || "",
      hidden: Boolean(payload.hidden),
      pageHtml: payload.page_html || "",
    })
    return
  }

  if (payload?.type === editorBridgeEventType.SELECTION && payload.selector) {
    const normalizedPayload = normalizeCanvasSelectionPayload(payload)
    canvasState.value = "connected"
    lastIncomingSelector.value = normalizedPayload.selector
    emit("select-candidate", normalizedPayload)
  }
}

watch(
  () => props.baseUrl,
  (value) => {
    canvasState.value = value ? "idle" : "idle"
    lastHoverSelector.value = ""
    lastIncomingSelector.value = ""
    lastFocusedSelector.value = ""
  }
)

watch(
  () => props.selectedSelector,
  () => {
    pushSelectedSelectorToCanvas()
  }
)

watch(
  () => props.previewOperations,
  () => {
    pushPreviewOperationsToCanvas()
  },
  { deep: true }
)

watch(
  () => props.feedbackSummary,
  () => {
    pushFeedbackSummaryToCanvas()
  },
  { deep: true }
)

watch(
  () => props.bridgeCommand,
  (value) => {
    if (!value) {
      return
    }

    runBridgeCommand(value)
  },
  { deep: true }
)

onMounted(() => {
  window.addEventListener("message", handleMessage)
})

onBeforeUnmount(() => {
  window.removeEventListener("message", handleMessage)
})
</script>

<style scoped>
.editor-canvas-frame {
  min-height: 100%;
}

.editor-canvas-frame__viewport {
  position: relative;
  min-height: calc(100vh - 72px);
  display: flex;
  justify-content: center;
  align-items: flex-start;
  overflow: hidden;
  background-color: #e2eaf4;
  background-image: radial-gradient(rgba(100, 116, 139, 0.18) 1px, transparent 1px);
  background-size: 22px 22px;
}

.editor-canvas-frame__iframe {
  width: 100%;
  min-height: calc(100vh - 72px);
  border: 0;
  background: white;
}

.editor-canvas-frame__viewport--desktop .editor-canvas-frame__iframe {
  width: 100%;
}

.editor-canvas-frame__viewport--tablet .editor-canvas-frame__iframe {
  width: min(820px, 100%);
  box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.1), 0 8px 32px rgba(15, 23, 42, 0.12);
}

.editor-canvas-frame__viewport--mobile .editor-canvas-frame__iframe {
  width: min(430px, 100%);
  box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.12), 0 12px 36px rgba(15, 23, 42, 0.14);
}

.editor-canvas-frame__empty {
  display: grid;
  place-items: center;
  min-height: 360px;
  padding: 24px;
  border: 1px dashed rgba(148, 163, 184, 0.42);
  border-radius: 24px;
  background:
    linear-gradient(180deg, rgba(248, 250, 252, 0.98), rgba(241, 245, 249, 0.98));
  text-align: center;
}

.editor-canvas-frame__empty-title {
  margin: 0;
  color: #0f172a;
  font-size: 18px;
  font-weight: 700;
}

.editor-canvas-frame__empty-body {
  max-width: 460px;
  margin: 10px 0 0;
  color: #64748b;
  font-size: 14px;
  line-height: 1.75;
}

.editor-canvas-frame__status-pill {
  position: absolute;
  bottom: 14px;
  right: 14px;
  z-index: 10;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px 5px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  pointer-events: none;
  backdrop-filter: blur(6px);
  transition: opacity 0.3s;
}

.editor-canvas-frame__status-pill--success {
  background: rgba(220, 252, 231, 0.88);
  color: #15803d;
  border: 1px solid rgba(134, 239, 172, 0.5);
}

.editor-canvas-frame__status-pill--info {
  background: rgba(224, 242, 254, 0.88);
  color: #0369a1;
  border: 1px solid rgba(147, 197, 253, 0.5);
}

.editor-canvas-frame__status-pill--warning {
  background: rgba(254, 249, 195, 0.88);
  color: #92400e;
  border: 1px solid rgba(253, 224, 71, 0.5);
}

.editor-canvas-frame__status-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}

.editor-canvas-frame__status-pill--success .editor-canvas-frame__status-dot {
  background: #16a34a;
}

.editor-canvas-frame__status-pill--info .editor-canvas-frame__status-dot {
  background: #0284c7;
}

.editor-canvas-frame__status-pill--warning .editor-canvas-frame__status-dot {
  background: #d97706;
  animation: status-pulse 1.6s ease-in-out infinite;
}

@keyframes status-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}
</style>
