import os
import json
import re
import gradio as gr

# ───────────────────── 1. 기본 설정 ─────────────────────
BEST_FILE, PER_PAGE = "best_games.json", 9   # ❶ 한 페이지에 9개씩


# ───────────────────── 2. BEST 데이터 ────────────────────
def _init_best():
    if not os.path.exists(BEST_FILE):
        json.dump([], open(BEST_FILE, "w"), ensure_ascii=False)


def _load_best():
    try:
        raw = json.load(open(BEST_FILE))
        return [u if isinstance(u, str) else u.get("url") for u in raw] if isinstance(raw, list) else []
    except Exception as e:
        print("BEST 로드 오류:", e)
        return []


def _save_best(lst):
    try:
        json.dump(lst, open(BEST_FILE, "w"), ensure_ascii=False, indent=2)
        return True
    except Exception as e:
        print("BEST 저장 오류:", e)
        return False


# *.hf.space → Hub URL(새 탭용) 변환
def to_hub_space_url(url: str) -> str:
    m = re.match(r"https?://([^-]+)-([^.]+)\.hf\.space(/.*)?", url)
    if m:
        owner, space, _ = m.groups()
        return f"https://huggingface.co/spaces/{owner}/{space}"
    return url


def add_url_to_best(url: str):
    data = _load_best()
    if url in data:
        return False
    data.insert(0, url)
    return _save_best(data)


# ───────────────────── 3. 유틸 ──────────────────────────
def page(lst, pg):
    s, e = (pg - 1) * PER_PAGE, (pg - 1) * PER_PAGE + PER_PAGE
    total = (len(lst) + PER_PAGE - 1) // PER_PAGE
    return lst[s:e], total


def process_url_for_iframe(url):
    """iframe용 주소 변환"""
    if "huggingface.co/spaces" in url:
        owner, name = url.rstrip("/").split("/spaces/")[1].split("/")[:2]
        return f"https://huggingface.co/spaces/{owner}/{name}/embed", "huggingface", []

    m = re.match(r"https?://([^/]+)\.hf\.space(/.*)?", url)
    if m:
        sub, rest = m.groups()
        static_url = f"https://{sub}.static.hf.space{rest or ''}"
        return static_url, "hfspace", [url]

    return url, "", []


# ───────────────────── 4. HTML 그리드 ───────────────────
def html(cards, pg, total):
    if not cards:
        return "<div style='text-align:center;padding:70px;color:#555;'>표시할 배포가 없습니다.</div>"

    css = r"""
    <style>
    /* 파스텔 배경 */
    body{
        margin:0;padding:0;font-family:Poppins,sans-serif;
        background:linear-gradient(135deg,#fdf4ff 0%,#f6fbff 50%,#fffaf4 100%);
        background-attachment:fixed;
        overflow-x:hidden;overflow-y:auto;
    }
    .container{width:100%;padding:10px 10px var(--bottom-gap,70px);box-sizing:border-box;}
    .grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;width:100%;}
    .card{
        background:#fff;border-radius:10px;overflow:hidden;box-shadow:0 4px 10px rgba(0,0,0,0.08);
        height:420px;display:flex;flex-direction:column;position:relative;
    }
    .frame{flex:1;position:relative;overflow:hidden;}
    .frame iframe{
        position:absolute;top:0;left:0;
        width:166.667%;height:166.667%;
        transform:scale(0.6);transform-origin:top left;border:0;
    }
    .frame.huggingface iframe{width:100%!important;height:100%!important;transform:none!important;border:none!important;}
    .frame.hfspace iframe{
        width:200%;height:200%;
        transform:scale(0.5);transform-origin:top left;border:0;
    }
    .foot{height:34px;display:flex;align-items:center;justify-content:center;background:#fafafa;border-top:1px solid #eee;}
    .foot a{font-size:0.85rem;font-weight:600;color:#4a6dd8;text-decoration:none;}
    .foot a:hover{text-decoration:underline;}
    @media(min-width:1200px){.card{height:560px;}}
    @media(max-width:767px){
        .grid{grid-template-columns:1fr;}
        .card{height:480px;}
    }
    </style>"""

    # 버튼과 헤더 높이를 고려해 스크롤 영역 동적으로 계산
    js = r"""
    <script>
    function adjustGap(){
      const header = document.querySelector('.app-header');
      const buttons = document.querySelector('.button-row');
      const gap = (buttons?.offsetHeight || 60) + 10; // 10px 여유
      document.documentElement.style.setProperty('--bottom-gap', gap + 'px');
      const content = document.getElementById('content-area');
      const h = (header?.offsetHeight || 0) + (buttons?.offsetHeight || 60);
      content.style.height = `calc(100vh - ${h}px)`;
    }
    window.addEventListener('load',adjustGap);
    window.addEventListener('resize',adjustGap);
    </script>
    """

    h = css + js + '<div class="container"><div class="grid">'
    for idx, url in enumerate(cards):
        iframe_url, extra_cls, alt_urls = process_url_for_iframe(url)
        frame_class = f"frame {extra_cls}".strip()
        iframe_id = f"iframe-{idx}-{hash(url)%10000}"
        alt_attr = f'data-alternate-urls="{",".join(alt_urls)}"' if alt_urls else ""
        safe_url = to_hub_space_url(url)
        h += f"""
        <div class="card">
          <div class="{frame_class}">
            <iframe id="{iframe_id}" src="{iframe_url}" loading="lazy"
              sandbox="allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads"
              data-original-url="{url}" {alt_attr}></iframe>
          </div>
          <div class="foot">
            <a href="{safe_url}" target="_blank" rel="noopener noreferrer">↗ Open in Full Screen (New Tab)</a>
          </div>
        </div>"""
    h += "</div></div>"
    h += f'<div class="page-info">Page {pg} / {total}</div>'
    return h


# ───────────────────── 5. Gradio UI ─────────────────────
def build():
    _init_best()

    header = """
    <style>
      .app-header{position:sticky;top:0;text-align:center;background:#fff;padding:16px 0 8px;border-bottom:1px solid #eee;z-index:1100;}
      .badge-row{display:inline-flex;gap:8px;margin:8px 0;}
    </style>
    <div class="app-header">
      <h1 style="margin:0;font-size:28px;">🎮 Vibe Game Gallery</h1>
      <p style="margin:4px 0;font-size:11px;">
        Only high-quality games automatically generated with <b>Vibe Game Craft</b> are showcased here.<br>
        Every game includes its full source code, and anyone can freely copy the <code>index.html</code>
        file from each URL and modify it as desired. All content is released under the <b>Apache&nbsp;2.0</b> license.
      </p>
      <div class="badge-row">
        <a href="https://huggingface.co/spaces/openfree/Vibe-Game" target="_blank">
          <img src="https://img.shields.io/static/v1?label=huggingface&message=Vibe%20Game%20Craft&color=800080&labelColor=ffa500&logo=huggingface&logoColor=ffff00&style=for-the-badge">
        </a>
        <a href="https://huggingface.co/spaces/openfree/Game-Gallery" target="_blank">
          <img src="https://img.shields.io/static/v1?label=huggingface&message=Game%20Gallery&color=800080&labelColor=ffa500&logo=huggingface&logoColor=ffff00&style=for-the-badge">
        </a>
        <a href="https://discord.gg/openfreeai" target="_blank">
          <img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=0000ff&labelColor=800080&logo=discord&logoColor=white&style=for-the-badge">
        </a>
      </div>
    </div>"""

    global_css = """
      footer{display:none !important;}
      .button-row{
        position:fixed!important;bottom:0!important;left:0!important;right:0!important;
        height:60px;background:#f0f0f0;padding:10px;text-align:center;
        box-shadow:0 -2px 10px rgba(0,0,0,.05);z-index:10000;
      }
      .button-row button{margin:0 10px;padding:10px 20px;font-size:16px;font-weight:bold;border-radius:50px;}
      #content-area{overflow-y:auto;}
    """

    with gr.Blocks(title="Vibe Game Gallery", css=global_css) as demo:
        gr.HTML(header)
        out = gr.HTML(elem_id="content-area")
        with gr.Row(elem_classes="button-row"):
            b_prev = gr.Button("◀ 이전", size="lg")
            b_next = gr.Button("다음 ▶", size="lg")

        bp = gr.State(1)

        def render(p=1):
            data, tot = page(_load_best(), p)
            return html(data, p, tot), p

        b_prev.click(lambda p: render(max(1, p-1)), inputs=bp, outputs=[out, bp])
        b_next.click(lambda p: render(p+1),      inputs=bp, outputs=[out, bp])

        demo.load(render, outputs=[out, bp])

    return demo


app = build()

if __name__ == "__main__":
    app.launch()