const caseData = {
  election: {
    kicker: "2.1 Election Broadcast",
    title: "2026 지방선거 방송 그래픽 / 데이터 송출 솔루션",
    client: "Yonhapnews TV / Local Stations",
    field: "Tornado3 / Karisma",
    status: "ELECT 2026",
    description: "6·3 지방선거 개표방송 화면 흐름을 기반으로, 지역민방별 선거구와 데이터 범위에 맞춘 실시간 그래픽 송출 시스템을 구성했습니다.",
    tags: ["Tornado3", "Karisma", "SBS API", "Regional CG"],
    statValue: "89 Cuts",
    statLabel: "지역민방용 Normal, Top, Bottom 그래픽 컷 구성",
    bullets: [
      "KNN, UBC, TBC, KBC, G1, TJB, JTV 지역 필터 기반 운영",
      "광역단체장, 교육감, 기초단체장 개표 데이터와 사전 투표율 화면 구성",
      "채널별 스케줄 큐, 반복 컷, 다음/대기/송출 상태를 분리한 운영 UI 개발"
    ],
    images: [
      { src: "assets/media/local-election-2026-suite.webp", alt: "2026 지방선거 지역민방 그래픽 쇼케이스" },
      { src: "assets/media/local-election-2026-race.webp", alt: "2026 지방선거 광역단체장 1위 후보 그래픽" },
      { src: "assets/media/local-election-2026-landscape.webp", alt: "2026 지방선거 기초단체장 판세 그래픽" }
    ]
  },
  virtual: {
    kicker: "2.2 Virtual Graphic",
    title: "버추얼 그래픽 솔루션",
    client: "Broadcast Studio",
    field: "VR / AR System",
    status: "3D READY",
    description: "Unreal Engine과 Unity를 활용해 VR, AR 기반의 실시간 3D 그래픽 시스템을 개발합니다.",
    tags: ["Unreal Engine", "Unity", "3D Data"],
    statValue: "VR / AR",
    statLabel: "실시간 데이터 기반 3D 그래픽 처리",
    bullets: [
      "Unreal Engine 기반 VR/AR 시스템 개발",
      "실시간 데이터 3D 그래픽 처리 시스템 적용",
      "Unity 활용 영상 콘텐츠 제작"
    ],
    images: [
      { src: "assets/media/virtual-election-studio.webp", alt: "버추얼 선거방송 스튜디오 그래픽" },
      { src: "assets/media/virtual-candidate-wall.webp", alt: "버추얼 후보자 데이터 월" },
      { src: "assets/media/virtual-debate-wall.webp", alt: "버추얼 토론 방송 그래픽 월" }
    ]
  },
  finance: {
    kicker: "2.3 Finance Broadcast",
    title: "증권 데이터 및 경제 방송 송출 그래픽 시스템",
    client: "Finance Media",
    field: "Database / API",
    status: "MARKET API",
    description: "코스콤 데이터와 해외 지수 데이터를 연계해 방송 송출 그래픽과 API 서버를 구현합니다.",
    tags: ["Koscom", "REST API", "DB Server"],
    statValue: "API",
    statLabel: "국내외 지수 데이터 연계 및 송출",
    bullets: [
      "코스콤 데이터와 해외 지수 연계 데이터베이스 서버 구축",
      "실시간 그래픽 연계 데이터 송수신 프로그램 개발",
      "REST 서버 API 구현 및 방송 송출 시스템 적용"
    ],
    images: [
      { src: "assets/media/finance-chart.webp", alt: "경제 방송 주가 차트 그래픽" },
      { src: "assets/media/finance-index.webp", alt: "경제 방송 지수 그래픽" },
      { src: "assets/media/finance-db-console.webp", alt: "경제 방송 데이터베이스 콘솔" }
    ]
  },
  ai: {
    kicker: "2.4 AI Vision",
    title: "AI 기반 거리 측정 시스템",
    client: "KPGA",
    field: "AI Learning",
    status: "AI RESULT",
    description: "KPGA 공식 기록에 사용되는 그린 홀 컵 간 거리 측정 솔루션을 개발했습니다.",
    tags: ["CUDA", "Deep Learning", "Coordinate"],
    statValue: "KPGA",
    statLabel: "공식 기록 환경에 적용된 거리 측정 솔루션",
    bullets: [
      "CUDA 기반 딥러닝 모델 학습",
      "카메라 영상 신호 수신 후 공 위치와 좌표 변환",
      "골프 중계와 기록 환경에 맞춘 AI 거리 측정"
    ],
    images: [
      { src: "assets/media/ai-distance-result.webp", alt: "AI 기반 거리 측정 결과 화면" },
      { src: "assets/media/ai-training-green.webp", alt: "골프 그린 AI 학습 화면" },
      { src: "assets/media/ai-detection-console.webp", alt: "AI 영상 분석 콘솔 화면" }
    ]
  },
  shopping: {
    kicker: "2.5 Commerce Broadcast",
    title: "홈쇼핑 자동화 송출 시스템 / 라이브 톡",
    client: "Commerce Channel",
    field: "Automation",
    status: "CONTROL",
    description: "송출 스케줄과 원격 제어, 모바일 연동을 포함한 홈쇼핑 방송 운영 시스템을 개발합니다.",
    tags: ["Remote Control", "Mobile", "Schedule"],
    statValue: "Automation",
    statLabel: "송출 스케줄과 모바일 운영 흐름 연동",
    bullets: [
      "송출 스케줄 관리 데이터 송수신 모듈 개발",
      "홈쇼핑 송출 프로그램 원격제어 로컬/모바일 연동",
      "웹 페이지와 앱을 활용한 실시간 방송 데이터 송출"
    ],
    images: [
      { src: "assets/media/shopping-control-dashboard.webp", alt: "홈쇼핑 송출 제어 대시보드" },
      { src: "assets/media/shopping-live-output.webp", alt: "홈쇼핑 라이브 방송 송출 화면" },
      { src: "assets/media/mobile-live-talk.webp", alt: "홈쇼핑 모바일 라이브 톡 화면" }
    ]
  },
  sports: {
    kicker: "2.6 Sports TV Graphic",
    title: "스포츠 / 게임 데이터 솔루션 송출 시스템",
    client: "Sports & Game",
    field: "TV Graphic",
    status: "UHD CG",
    description: "Live Data를 자막시스템에서 사용 가능한 형태로 변환하고 다양한 종목의 TVG 시스템을 제작합니다.",
    tags: ["HD/UHD", "International Signal", "Scorebug"],
    statValue: "IS",
    statLabel: "국제신호 제작과 고해상도 CG 송출 대응",
    bullets: [
      "HD/UHD급 CG 제작과 국제신호 제작",
      "3D/2D Cut, 애니메이션 등 특수 효과 적용",
      "구기, 투기, 계측 종목 등 다양한 스포츠 TVG 구성"
    ],
    images: [
      { src: "assets/media/sports-game-result.webp", alt: "게임 결과 방송 그래픽" },
      { src: "assets/media/sports-player-profile.webp", alt: "선수 프로필 방송 그래픽" },
      { src: "assets/media/football-scorebug.webp", alt: "축구 스코어버그 방송 그래픽" }
    ]
  }
};

const body = document.body;
const header = document.getElementById("siteHeader");
const mobilePanel = document.getElementById("mobilePanel");
const menuToggle = document.querySelector(".menu-toggle");
const cursor = document.querySelector(".cursor");
const loaderBar = document.getElementById("loaderBar");
const loaderValue = document.getElementById("loaderValue");
const caseStage = document.querySelector(".case-stage");
const caseImage = document.getElementById("caseImage");
const caseKicker = document.getElementById("caseKicker");
const caseName = document.getElementById("caseName");
const caseDescription = document.getElementById("caseDescription");
const caseBullets = document.getElementById("caseBullets");
const caseThumbs = document.getElementById("caseThumbs");
const caseClient = document.getElementById("caseClient");
const caseField = document.getElementById("caseField");
const caseStatus = document.getElementById("caseStatus");
const caseTags = document.getElementById("caseTags");
const caseStatValue = document.getElementById("caseStatValue");
const caseStatLabel = document.getElementById("caseStatLabel");
const navLinks = [...document.querySelectorAll(".primary-nav a")];

let loaderProgress = 0;
const finishLoading = () => {
  body.classList.remove("is-loading");
  body.classList.add("is-ready");
};

if (loaderBar && loaderValue) {
  const loaderTimer = window.setInterval(() => {
    loaderProgress = Math.min(loaderProgress + Math.ceil(Math.random() * 12), 100);
    loaderBar.style.width = `${loaderProgress}%`;
    loaderValue.textContent = String(loaderProgress).padStart(2, "0");
    if (loaderProgress >= 100) {
      window.clearInterval(loaderTimer);
      window.setTimeout(finishLoading, 220);
    }
  }, 55);
} else {
  finishLoading();
}

const updateScrollState = () => {
  if (!header) return;

  const scrollTop = window.scrollY || document.documentElement.scrollTop;
  const scrollable = document.documentElement.scrollHeight - window.innerHeight;
  const progress = scrollable > 0 ? (scrollTop / scrollable) * 100 : 0;
  header.classList.toggle("is-scrolled", scrollTop > 20);
  header.style.setProperty("--page-progress", `${progress}%`);

  let currentHref = navLinks[0]?.getAttribute("href");
  navLinks.forEach(link => {
    const target = document.querySelector(link.getAttribute("href"));
    if (target && target.getBoundingClientRect().top <= window.innerHeight * 0.45) {
      currentHref = link.getAttribute("href");
    }
  });
  navLinks.forEach(link => {
    link.setAttribute("aria-current", link.getAttribute("href") === currentHref ? "true" : "false");
  });
};

window.addEventListener("scroll", updateScrollState, { passive: true });
window.addEventListener("resize", updateScrollState);
updateScrollState();

const revealObserver = new IntersectionObserver(
  entries => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        entry.target.classList.add("in-view");
        revealObserver.unobserve(entry.target);
      }
    });
  },
  { threshold: 0.16 }
);

document.querySelectorAll(".reveal").forEach(element => revealObserver.observe(element));

const setMenuOpen = open => {
  if (!menuToggle || !mobilePanel) return;

  menuToggle.setAttribute("aria-expanded", String(open));
  menuToggle.setAttribute("aria-label", open ? "메뉴 닫기" : "메뉴 열기");
  mobilePanel.classList.toggle("is-open", open);
  mobilePanel.setAttribute("aria-hidden", String(!open));
  menuToggle.innerHTML = `<i data-lucide="${open ? "x" : "menu"}"></i>`;
  if (window.lucide) window.lucide.createIcons();
};

if (menuToggle) {
  menuToggle.addEventListener("click", () => {
    const open = menuToggle.getAttribute("aria-expanded") !== "true";
    setMenuOpen(open);
  });
}

mobilePanel?.querySelectorAll("a").forEach(link => {
  link.addEventListener("click", () => setMenuOpen(false));
});

const fillList = (element, items, tagName = "span") => {
  if (!element) return;
  const nodes = items.map(item => {
    const node = document.createElement(tagName);
    node.textContent = item;
    return node;
  });
  element.replaceChildren(...nodes);
};

const renderCase = (key, imageIndex = 0) => {
  const data = caseData[key];
  if (!data || !caseImage) return;

  const image = data.images[imageIndex] || data.images[0];
  caseStage?.classList.add("is-switching");
  window.setTimeout(() => caseStage?.classList.remove("is-switching"), 180);

  caseImage.src = image.src;
  caseImage.alt = image.alt;
  if (caseKicker) caseKicker.textContent = data.kicker;
  if (caseName) caseName.textContent = data.title;
  if (caseDescription) caseDescription.textContent = data.description;
  if (caseClient) caseClient.textContent = data.client;
  if (caseField) caseField.textContent = data.field;
  if (caseStatus) caseStatus.textContent = data.status;
  if (caseStatValue) caseStatValue.textContent = data.statValue;
  if (caseStatLabel) caseStatLabel.textContent = data.statLabel;
  fillList(caseTags, data.tags);
  fillList(caseBullets, data.bullets, "li");

  if (caseThumbs) {
    const buttons = data.images.map((item, index) => {
      const button = document.createElement("button");
      button.type = "button";
      button.className = index === imageIndex ? "is-active" : "";
      button.dataset.caseThumb = String(index);
      button.setAttribute("aria-label", item.alt);

      const thumb = document.createElement("img");
      thumb.src = item.src;
      thumb.alt = "";
      button.appendChild(thumb);
      button.addEventListener("click", () => renderCase(key, index));
      return button;
    });
    caseThumbs.replaceChildren(...buttons);
  }
};

document.querySelectorAll(".case-tabs button").forEach(button => {
  button.addEventListener("click", () => {
    document.querySelectorAll(".case-tabs button").forEach(item => {
      item.classList.remove("is-active");
      item.setAttribute("aria-selected", "false");
    });
    button.classList.add("is-active");
    button.setAttribute("aria-selected", "true");
    renderCase(button.dataset.case);
  });
});

renderCase("election");

if (window.matchMedia("(pointer: fine)").matches && cursor) {
  window.addEventListener("pointermove", event => {
    cursor.style.transform = `translate3d(${event.clientX}px, ${event.clientY}px, 0) translate(-50%, -50%)`;
    cursor.classList.add("is-visible");
  });

  document.querySelectorAll("a, button").forEach(element => {
    element.addEventListener("pointerenter", () => cursor.classList.add("is-active"));
    element.addEventListener("pointerleave", () => cursor.classList.remove("is-active"));
  });
}

window.addEventListener("keydown", event => {
  if (event.key === "Escape") setMenuOpen(false);
});

if (window.lucide) {
  window.lucide.createIcons();
}
