<script setup lang="ts">
  import type { PageDataTemplateComponents } from '#layers/types/api/pageData'
  
  interface Props {
    components: PageDataTemplateComponents
    pageVerTmplSeq: number
  }
  
  const props = defineProps<Props>()
  const { sendLog } = useAnalytics()
  const { tm, locale } = useI18n()
  const customContainerRef = ref<HTMLElement | null>(null)
  const nuxtApp = useNuxtApp()
  // Configuration
  const runtimeConfig = useRuntimeConfig()
  const staticUrl = runtimeConfig.public.staticUrl

  const coerceToString = (value: unknown): string => {
    if (typeof value === 'string') return value
    if (typeof value === 'number') return String(value)
    if (typeof value === 'boolean') return value ? 'true' : 'false'
    return ''
  }

  // URL인지 확인하는 함수
  const isUrl = (str: string): boolean => {
    try {
      const url = new URL(str)
      return url.protocol === 'http:' || url.protocol === 'https:'
    } catch {
      return false
    }
  }

  // API로 내려온 "HTML 문자열" 내부의 {{ tm('key') }} 형태를 현재 locale 기준 번역 문자열로 치환
  // (Vue 템플릿 컴파일이 일어나지 않으므로 사전 치환이 필요)
  const applyI18nToApiHtml = (html: string): string => {
    // locale 변경 시 computed가 재평가되도록 의존성 연결
    // eslint-disable-next-line @typescript-eslint/no-unused-expressions
    locale.value

    return html.replace(
      /\{\{\s*tm\(\s*(["'])([^"']+)\1\s*\)\s*\}\}/g,
      (_full, _q, key: string) => coerceToString(tm(key)),
    )
  }
  
  // fetch한 HTML을 저장할 ref
  const fetchedHtml = ref<string>('')
  const isLoadingHtml = ref(false)

  // URL에서 HTML 가져오기
  const fetchHtmlFromUrl = async (url: string): Promise<string> => {
    try {
      isLoadingHtml.value = true
      const response = await $fetch<string>(url, {
        method: 'GET',
        headers: {
          'Accept': 'text/html',
        },
      })
      return typeof response === 'string' ? response : JSON.stringify(response)
    } catch (error: any) {
      // eslint-disable-next-line no-console
      console.error('[Exception] Failed to fetch custom HTML:', error)
      return ''
    } finally {
      isLoadingHtml.value = false
    }
  }

  // HTML 주석에서 customTranslang JSON URL 추출
  // 형식: <!-- customTranslang: https://example.com/translations.json -->
  const extractCustomTranslangUrl = (html: string): string | null => {
    const commentRegex = /<!--\s*customTranslang\s*:\s*([^\s]+)\s*-->/i
    const match = html.match(commentRegex)
    return match && match[1] ? match[1].trim() : null
  }

  // JSON 파일을 fetch해서 i18n에 추가
  const loadCustomTranslations = async (jsonUrl: string): Promise<void> => {
    try {
      const $i18n = nuxtApp.$i18n as any
      if (!$i18n) {
        // eslint-disable-next-line no-console
        console.warn('[CustomTranslations] i18n instance not found')
        return
      }

      const translations = await $fetch<Record<string, any>>(jsonUrl, {
        method: 'GET',
        headers: {
          'Accept': 'application/json',
        },
      })

      if (!translations || typeof translations !== 'object') {
        // eslint-disable-next-line no-console
        console.warn('[CustomTranslations] Invalid translation data:', translations)
        return
      }

      // 로케일 코드 변환 맵 (소문자 하이픈 -> 대문자 하이픈)
      const localeMap: Record<string, string> = {
        'zh-tw': 'zh-TW',
        'zh-cn': 'zh-CN',
      }

      // 현재 locale에 해당하는 번역 데이터 찾기
      const currentLocale = locale.value
      const normalizedLocale = localeMap[currentLocale] || currentLocale

      // 대소문자 구분 없이 로케일 데이터 찾기
      const localeData =
        translations[normalizedLocale] ||
        translations[normalizedLocale.toLowerCase()] ||
        translations[currentLocale] ||
        translations[currentLocale.toLowerCase()]

      if (localeData && typeof localeData === 'object') {
        // 기존 메시지에 병합 (기존 키는 유지하고 새로운 키만 추가)
        const existingMessages = $i18n.getLocaleMessage(currentLocale) || {}
        $i18n.setLocaleMessage(currentLocale, {
          ...existingMessages,
          ...localeData,
        })
        // eslint-disable-next-line no-console
        console.log('[CustomTranslations] Loaded translations for locale:', currentLocale)
      }
    } catch (error: any) {
      // eslint-disable-next-line no-console
      console.error('[Exception] Failed to load custom translations:', error)
    }
  }

  // custom_contents가 URL인지 확인하고 HTML 가져오기
  watch(
    () => {
      // 타입 가드: 단일 컴포넌트 패턴인지 확인
      if ('group_sets' in props.components) {
        return null
      }
      const customContents = props.components.customContents
      const firstGroup = customContents?.groups?.[0]
      if (!firstGroup) {
        return null
      }
      // res_path는 PageDataResourceGroup의 직접 속성
      // 또는 btn_info.detail.res_path 형태일 수 있음
      const resPath = (firstGroup as any).detail?.res_path
      if (!resPath) {
        return null
      }
      
      // 문자열로 변환
      const resPathStr = String(resPath)
      // 마지막에 "/contents" 또는 "contents"가 있으면 제거
      const cleanedResPath = resPathStr.replace(/\/?contents\/?$/, '')
      return cleanedResPath
    },
    async (cleanedResPath) => {
      if (!cleanedResPath) {
        fetchedHtml.value = ''
        return
      }

      const contentStr = typeof cleanedResPath === 'string' ? `${staticUrl}${cleanedResPath}/index.html` : String(`${staticUrl}${cleanedResPath}/index.html`)
      console.log("🚀 ~ contentStr:", contentStr)
      
      let html = ''
      if (isUrl(contentStr)) {
        // URL인 경우 fetch
        html = await fetchHtmlFromUrl(contentStr)
      } else {
        // HTML 문자열인 경우 그대로 사용
        html = contentStr
      }

      fetchedHtml.value = html

      // HTML 주석에서 customTranslang JSON URL 추출 및 로드
      if (html) {
        const jsonUrl = extractCustomTranslangUrl(html)
        if (jsonUrl) {
          await loadCustomTranslations(jsonUrl)
        }
      }
    },
    { immediate: true },
  )

  // locale 변경 시에도 custom translations 다시 로드
  watch(
    () => locale.value,
    async () => {
      if (fetchedHtml.value) {
        const jsonUrl = extractCustomTranslangUrl(fetchedHtml.value)
        if (jsonUrl) {
          await loadCustomTranslations(jsonUrl)
        }
      }
    },
  )
  
  // API HTML 원본 (i18n만 치환) - asset(link/style/script) 추출용
  const customContentsRaw = computed(() => {
    if (!fetchedHtml.value) return ''
    
    let html = fetchedHtml.value

    // i18n 치환 ({{ tm('...') }})
    html = applyI18nToApiHtml(html)
    return html
  })

  // 렌더링용 HTML
  // - link/script는 head/body로 별도 주입 (렌더 위치에 남기지 않음)
  // - style은 "그 자리에 그대로" 렌더링하되, 적용 안정성을 위해 head에도 복제 주입함
  const customContentsHtml = computed(() => {
    const html = customContentsRaw.value
    if (!html) return ''

    return html
      // link 태그 제거
      .replace(/<link\b[^>]*>/gi, '')
      // script 블록 제거
      .replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, '')
  })
  
  type OrderedAsset =
    | { kind: 'link'; href: string; rel?: string | null; media?: string | null; integrity?: string | null; crossOrigin?: string | null; referrerPolicy?: string | null }
    | { kind: 'script'; src: string; type?: string | null; integrity?: string | null; crossOrigin?: string | null; referrerPolicy?: string | null }
    | { kind: 'style'; cssText: string }
  
  const parseTagAttributes = (tagHtml: string): Record<string, string> => {
    const attrs: Record<string, string> = {}
    const attrRegex = /([^\s=]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+))/g
    let m: RegExpExecArray | null
    while ((m = attrRegex.exec(tagHtml)) !== null) {
      const key = m[1]?.toLowerCase()
      const value = (m[2] ?? m[3] ?? m[4] ?? '').trim()
      if (key) attrs[key] = value
    }
    return attrs
  }

  // asset(link/script) 주입 위치: main 우선, 없으면 body fallback
  const getAssetMountEl = (): HTMLElement => {
    if (!import.meta.client) {
      // SSR에서는 호출되지 않지만 타입 안정성을 위해
      return {} as HTMLElement
    }
    return (document.querySelector('main') as HTMLElement | null) ?? document.body
  }
  
  // custom_contents 원본 문자열에서 link/script를 "작성된 순서" 그대로 추출 (파서가 위치를 바꾸는 문제 방지)
  const extractOrderedAssets = (html: string): OrderedAsset[] => {
    const assets: OrderedAsset[] = []

    // link/script 시작 태그 + style 블록 전체를 한 번에 매칭 (작성된 순서 보존)
    const tagRegex = /<(link|script)\b[^>]*>|<style\b[^>]*>[\s\S]*?<\/style>/gi
    let match: RegExpExecArray | null
    while ((match = tagRegex.exec(html)) !== null) {
      const tagHtml = match[0] || ''
      const tagName = (match[1] || '').toLowerCase()

      // style 블록
      if (/^<style\b/i.test(tagHtml)) {
        const cssText = tagHtml
          .replace(/^<style\b[^>]*>/i, '')
          .replace(/<\/style>\s*$/i, '')
        if (cssText.trim()) {
          assets.push({ kind: 'style', cssText })
        }
        continue
      }

      const attrs = parseTagAttributes(tagHtml)

      if (tagName === 'link') {
        const href = attrs.href
        if (!href) continue
        assets.push({
          kind: 'link',
          href,
          rel: attrs.rel ?? null,
          media: attrs.media ?? null,
          integrity: attrs.integrity ?? null,
          crossOrigin: attrs.crossorigin ?? null,
          referrerPolicy: attrs.referrerpolicy ?? null,
        })
        continue
      }

      if (tagName === 'script') {
        const src = attrs.src
        if (!src) continue
        assets.push({
          kind: 'script',
          src,
          type: attrs.type ?? null,
          integrity: attrs.integrity ?? null,
          crossOrigin: attrs.crossorigin ?? null,
          referrerPolicy: attrs.referrerpolicy ?? null,
        })
      }
    }

    return assets
  }
  
  // CSS 파일 동적 로드
  const loadStylesheet = (asset: Extract<OrderedAsset, { kind: 'link' }>): Promise<void> => {
    return new Promise((resolve, reject) => {
      if (!import.meta.client) {
        resolve()
        return
      }
  
      const href = asset.href
      // 이미 로드된 스타일시트 확인
      const existingLink = document.querySelector(`link[href="${href}"]`)
      if (existingLink) {
        resolve()
        return
      }
      
      const link = document.createElement('link')
      link.rel = asset.rel || 'stylesheet'
      link.href = href
      if (asset.media) link.media = asset.media
      if (asset.integrity) link.integrity = asset.integrity
      if (asset.crossOrigin) link.crossOrigin = asset.crossOrigin
      if (asset.referrerPolicy) link.referrerPolicy = asset.referrerPolicy
      link.onload = () => resolve()
      link.onerror = () => reject(new Error(`Failed to load stylesheet: ${href}`))
      getAssetMountEl().appendChild(link)
    })
  }
  
  // JS 파일 동적 로드
  const loadScript = (asset: Extract<OrderedAsset, { kind: 'script' }>): Promise<void> => {
    return new Promise((resolve, reject) => {
      if (!import.meta.client) {
        resolve()
        return
      }
  
      const src = asset.src
      // 이미 로드된 스크립트 확인
      const existingScript = document.querySelector(`script[src="${src}"]`)
      if (existingScript) {
        resolve()
        return
      }
      
      const script = document.createElement('script')
      script.src = src
      // 순서 보장을 위해 async=false
      script.async = false
      if (asset.type) script.type = asset.type
      if (asset.integrity) script.integrity = asset.integrity
      if (asset.crossOrigin) script.crossOrigin = asset.crossOrigin
      if (asset.referrerPolicy) script.referrerPolicy = asset.referrerPolicy
      script.onload = () => resolve()
      script.onerror = () => reject(new Error(`Failed to load script: ${src}`))
      getAssetMountEl().appendChild(script)
    })
  }

  // 문자열 해시(간단) - style 중복 주입 방지용
  const hashString = (str: string): string => {
    let hash = 5381
    for (let i = 0; i < str.length; i++) {
      hash = (hash * 33) ^ str.charCodeAt(i)
    }
    // unsigned 32-bit
    return (hash >>> 0).toString(16)
  }

  // inline <style> 주입 (작성 순서 보존 + 중복 방지)
  const loadInlineStyle = (asset: Extract<OrderedAsset, { kind: 'style' }>): void => {
    if (!import.meta.client) return
    const cssText = asset.cssText || ''
    const key = hashString(cssText)

    const existing = document.head.querySelector(`style[data-custom-style-hash="${key}"]`)
    if (existing) return

    const styleEl = document.createElement('style')
    styleEl.setAttribute('data-custom-style-hash', key)
    styleEl.textContent = cssText
    getAssetMountEl().appendChild(styleEl)
  }
  
  // 스크립트 로드 완료 여부 추적
  const scriptsLoaded = ref(false)
  
  const modalStore = useModalStore()

  // API HTML에서 onclick으로 호출할 수 있도록 window에 노출할 "단일 함수"
  // - 인자 방식: onclick="window.__customAction('open-confirm', '내용', '확인', '취소', '로그값')"
  // - dataset 방식도 호환: onclick="window.__customAction(this)"
  const handleCustomAction = (
    actionOrEl: string | HTMLElement | null,
    rawContent?: string,
    confirmText?: string,
    cancelText?: string,
    logValue?: string,
  ) => {
    if (!import.meta.client) return
    if (!actionOrEl) return

    const action =
      typeof actionOrEl === 'string'
        ? actionOrEl
        : actionOrEl.getAttribute('data-action') || ''

    const contentRaw =
      typeof actionOrEl === 'string'
        ? rawContent || ''
        : actionOrEl.getAttribute('data-content') ||
          actionOrEl.getAttribute('data-confirm-content') ||
          ''

    const confirmButtonText =
      typeof actionOrEl === 'string'
        ? confirmText || ''
        : actionOrEl.getAttribute('data-confirm-text') || ''

    const cancelButtonText =
      typeof actionOrEl === 'string'
        ? cancelText || ''
        : actionOrEl.getAttribute('data-cancel-text') || ''

    const analyticsLogValue =
      typeof actionOrEl === 'string'
        ? logValue || ''
        : actionOrEl.getAttribute('data-log') || ''

    // 1) open-confirm
    if (action === 'open-confirm') {
      const contentText = contentRaw ? applyI18nToApiHtml(contentRaw) : ''
      if (contentText) {
        modalStore.handleOpenConfirm({
          contentText,
          ...(confirmButtonText ? { confirmButtonText } : {}),
          ...(cancelButtonText ? { cancelButtonText } : {}),
        })
      }
    }
    if (action === 'open-alert') {
      const contentText = contentRaw ? applyI18nToApiHtml(contentRaw) : ''
      if (contentText) {
        modalStore.handleOpenAlert({
          contentText,
          ...(confirmButtonText ? { confirmButtonText } : {}),
          ...(cancelButtonText ? { cancelButtonText } : {}),
        })
      }
    }

    // 2) analytics
    if (analyticsLogValue) {
      console.log("🚀 ~ handleCustomAction ~ analyticsLogValue:", analyticsLogValue)
      sendLog(locale.value, analyticsLogValue)
    }
  }
  
  // custom_contents 변경 시 link/script를 "작성된 순서"대로 순차 로드
  watch(
    () => customContentsRaw.value,
    async (html, _prev, onCleanup) => {
      if (!import.meta.client) return
      if (!html) return
  
      scriptsLoaded.value = false
  
      let cancelled = false
      onCleanup(() => {
        cancelled = true
      })
  
      const assets = extractOrderedAssets(html)
      for (const asset of assets) {
        if (cancelled) return
        try {
          if (asset.kind === 'link') {
            await loadStylesheet(asset)
          } else if (asset.kind === 'style') {
            loadInlineStyle(asset)
          } else {
            await loadScript(asset)
          }
        } catch (err) {
          // eslint-disable-next-line no-console
          console.warn(`${asset.kind} load error:`, err)
        }
      }
  
      if (!cancelled) scriptsLoaded.value = true
    },
    { immediate: true },
  )
  
  // onMounted에서 초기화 코드 실행
  onMounted(() => {
    if (!import.meta.client) return

    const container = customContainerRef.value
    if (!container) return

    // onclick="window.__customAction(this)" 지원
    ;(window as any).__customAction = handleCustomAction

    // onclick을 못 쓰는 케이스 대비: 이벤트 위임도 같이 지원
    const onDelegatedClick = (e: MouseEvent) => {
      const target = e.target as HTMLElement | null
      const el =
        (target?.closest?.('[data-action], [data-log]') as HTMLElement | null) ??
        null
      handleCustomAction(el)
    }

    container.addEventListener('click', onDelegatedClick)
    onBeforeUnmount(() => {
      container.removeEventListener('click', onDelegatedClick)
    })
  })

  onBeforeUnmount(() => {
    if (!import.meta.client) return
    const w = window as any
    if (w.__customAction === handleCustomAction) {
      delete w.__customAction
    }
  })
  </script>
  
  <template>
    <section class="section-standard">
      <div
        v-if="customContentsHtml"
        ref="customContainerRef"
        v-dompurify-admin="customContentsHtml"
        class="custom-container"
      ></div>
      <div
        class="custom-container"
      >
    {{ tm('Newreturnevent_Section03_Title') }}
    </div>
    </section>
  </template>
  
  
  <style>
  .custom-container {
    min-height: 20rem;
    background-color: #fff;
  }
  </style>
