// 타운카 제휴업체 — UI 프리미티브
// Design System: Towncar

// ── Towncar 디자인 토큰
const TC = {
  primary: '#0BB53B',
  primaryPressed: '#06842B',
  primarySubtle: 'rgba(11,181,59,0.10)',
  brandMint: '#00C8B1',
  brandMintLight: '#00E0AB',
  textStrong: '#000000',
  text: 'rgba(23,23,25,0.82)',
  textNeutral: 'rgba(23,23,25,0.55)',
  textAlt: 'rgba(23,23,25,0.30)',
  textAssist: 'rgba(23,23,25,0.22)',
  textDisabled: 'rgba(23,23,25,0.10)',
  line: 'rgba(112,115,124,0.22)',
  lineSoft: 'rgba(112,115,124,0.10)',
  fillSubtle: 'rgba(111,110,116,0.05)',
  fill: 'rgba(111,110,116,0.08)',
  fillStrong: 'rgba(111,110,116,0.12)',
  white: '#FFFFFF',
  surface: '#FFFFFF',
  bgBase: '#F8F8F9',
  // accents
  red: '#E41F10',
  orange: '#FD6106',
  blue: '#008AED',
  yellow: '#F5B900',
  purple: '#8E58F0',
  pink: '#FF5786',
  // dimmer
  dim: 'rgba(23,23,25,0.55)',
};

const FF = '"Pretendard Variable", -apple-system, system-ui, sans-serif';

// ── 마우스 드래그로 가로 스크롤 지원 (웹 PC용)
// 사용법: const dragProps = useDragScroll(); <div ref={dragProps.ref} {...dragProps.handlers}>
function useDragScroll() {
  const ref = React.useRef(null);
  const state = React.useRef({ down: false, startX: 0, scrollLeft: 0, moved: false, prevSnap: '' });

  // 부드러운 스냅 애니메이션 (480ms ease-out)
  const animateTo = (el, target) => {
    const start = el.scrollLeft;
    const distance = target - start;
    if (Math.abs(distance) < 1) return;
    const duration = 480;
    const startTime = performance.now();
    const ease = t => 1 - Math.pow(1 - t, 3);
    const tick = (now) => {
      const t = Math.min(1, (now - startTime) / duration);
      el.scrollLeft = start + distance * ease(t);
      if (t < 1) requestAnimationFrame(tick);
      else el.style.scrollSnapType = state.current.prevSnap;
    };
    requestAnimationFrame(tick);
  };

  // 가장 가까운 스냅 위치 계산 (자식 요소의 offsetLeft 기준)
  const findNearestSnap = (el) => {
    const children = el.children;
    if (!children.length) return el.scrollLeft;
    const current = el.scrollLeft;
    // 컨테이너 안쪽 padding-left를 보정
    const padLeft = parseFloat(getComputedStyle(el).paddingLeft) || 0;
    let best = current, bestDist = Infinity;
    for (const c of children) {
      const snapX = c.offsetLeft - padLeft;
      const d = Math.abs(snapX - current);
      if (d < bestDist) { bestDist = d; best = snapX; }
    }
    return best;
  };

  const onPointerDown = (e) => {
    if (e.pointerType !== 'mouse') return;
    const el = ref.current;
    if (!el) return;
    state.current = {
      down: true, startX: e.clientX, scrollLeft: el.scrollLeft, moved: false,
      prevSnap: el.style.scrollSnapType || '',
    };
    el.style.scrollSnapType = 'none';
  };
  const finishDrag = () => {
    const s = state.current;
    if (!s.down) return;
    s.down = false;
    const el = ref.current;
    if (!el) return;
    // 스냅이 켜져있는 컨테이너만 부드러운 정렬 수행
    const snap = s.prevSnap;
    if (snap && snap !== 'none' && s.moved) {
      const target = findNearestSnap(el);
      animateTo(el, target);
    } else {
      el.style.scrollSnapType = s.prevSnap;
    }
  };
  const onPointerMove = (e) => {
    if (e.pointerType !== 'mouse') return;
    const s = state.current;
    if (!s.down) return;
    const dx = e.clientX - s.startX;
    if (Math.abs(dx) > 3) s.moved = true;
    const el = ref.current;
    if (el) el.scrollLeft = s.scrollLeft - dx;
  };
  const onPointerUp = (e) => {
    if (e.pointerType !== 'mouse') return;
    finishDrag();
  };
  const onClickCapture = (e) => {
    if (state.current.moved) {
      e.stopPropagation();
      e.preventDefault();
      state.current.moved = false;
    }
  };
  return {
    ref,
    handlers: {
      onPointerDown, onPointerMove, onPointerUp,
      onPointerLeave: onPointerUp, onPointerCancel: onPointerUp,
      onClickCapture,
    },
  };
}

// ── Lucide 아이콘 래퍼
function _toPascal(s) {
  return s.split('-').map(p => p.charAt(0).toUpperCase() + p.slice(1)).join('');
}
function Icon({ name, size = 24, stroke = 1.8, color = 'currentColor', fill = 'none', style = {} }) {
  const key = _toPascal(name);
  const i = window.lucide && window.lucide[key];
  if (!i) return <span style={{ width: size, height: size, display: 'inline-block', ...style }} />;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill} stroke={color}
      strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round"
      style={{ flexShrink: 0, ...style }}
      dangerouslySetInnerHTML={{ __html: i.map(([tag, attrs]) =>
        `<${tag} ${Object.entries(attrs).map(([k,v])=>`${k}="${v}"`).join(' ')}/>`
      ).join('') }}
    />
  );
}

// ── 페이지 헤더 (webview용)
function PageHeader({ title, onLeading, leadingIcon = 'chevron-left', trailing }) {
  return (
    <div style={{
      height: 52, padding: '0 8px',
      display: 'flex', alignItems: 'center', gap: 8,
      background: '#fff',
      borderBottom: '0.5px solid ' + TC.line,
      position: 'sticky', top: 0, zIndex: 30,
      fontFamily: FF,
    }}>
      <button onClick={onLeading} style={{
        all: 'unset', cursor: 'pointer', width: 40, height: 40,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }} aria-label="뒤로/닫기">
        <Icon name={leadingIcon} size={leadingIcon === 'x' ? 22 : 26}
              color={TC.textStrong} stroke={leadingIcon === 'x' ? 2.2 : 2} />
      </button>
      <h1 style={{
        margin: 0, flex: 1, fontSize: 17, fontWeight: 700, letterSpacing: '-0.020em',
        color: TC.textStrong, textAlign: 'center',
        paddingRight: trailing ? 0 : 40,
      }}>{title}</h1>
      {trailing ? (
        <div style={{ width: 40, height: 40, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
          {trailing}
        </div>
      ) : null}
    </div>
  );
}

// ── 카테고리 탭 (상단)
function CategoryTabs({ items, active, onChange, counts }) {
  const drag = useDragScroll();
  const scrollRef = drag.ref;
  const activeRef = React.useRef(null);

  // 활성 탭으로 자동 스크롤 (가운데 정렬)
  React.useEffect(() => {
    const el = activeRef.current;
    const container = scrollRef.current;
    if (!el || !container) return;
    const target = el.offsetLeft - (container.clientWidth - el.offsetWidth) / 2;
    container.scrollTo({ left: Math.max(0, target), behavior: 'smooth' });
  }, [active]);

  return (
    <div style={{
      background: '#fff',
      borderBottom: '0.5px solid ' + TC.line,
      position: 'sticky', top: 52, zIndex: 25,
      fontFamily: FF,
    }}>
      <div ref={scrollRef} {...drag.handlers} style={{
        display: 'flex', overflowX: 'auto', overflowY: 'hidden',
        scrollbarWidth: 'none',
        padding: '0 12px',
        cursor: 'grab',
      }} className="hide-scroll">
        {items.map(it => {
          const on = it.id === active;
          return (
            <button key={it.id}
              ref={on ? activeRef : null}
              onClick={() => onChange(it.id)} style={{
              all: 'unset', cursor: 'pointer',
              padding: '14px 12px 12px',
              display: 'inline-flex', flexDirection: 'column', alignItems: 'center', gap: 5,
              position: 'relative', flexShrink: 0,
              color: on ? TC.textStrong : TC.textNeutral,
            }}>
              <span style={{
                fontSize: 14, fontWeight: on ? 700 : 500, letterSpacing: '-0.010em',
                whiteSpace: 'nowrap',
              }}>{it.label}
                {counts && counts[it.id] != null && (
                  <span style={{
                    marginLeft: 4, fontSize: 12, fontWeight: 500,
                    color: on ? TC.primary : TC.textAlt,
                  }}>{counts[it.id]}</span>
                )}
              </span>
              {on && (
                <span style={{
                  position: 'absolute', bottom: 0, left: 6, right: 6,
                  height: 3, background: TC.textStrong, borderRadius: 2,
                }} />
              )}
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ── 서브 필터 칩 (브랜드 / 기타 하위)
function SubChips({ items, active, onChange, showAll = true }) {
  const all = showAll ? [{ id: '__all', label: '전체' }, ...items] : items;
  const drag = useDragScroll();
  return (
    <div style={{
      background: '#fff',
      borderBottom: '0.5px solid ' + TC.line,
      fontFamily: FF,
    }}>
      <div ref={drag.ref} {...drag.handlers} style={{
        display: 'flex', gap: 6, overflowX: 'auto',
        padding: '10px 16px',
        scrollbarWidth: 'none',
        cursor: 'grab',
      }} className="hide-scroll">
        {all.map(it => {
          const on = (active == null && it.id === '__all') || it.id === active;
          return (
            <button key={it.id} onClick={() => onChange(it.id === '__all' ? null : it.id)} style={{
              all: 'unset', cursor: 'pointer', flexShrink: 0,
              height: 32, padding: '0 14px',
              borderRadius: 999,
              background: on ? TC.textStrong : '#fff',
              border: on ? '1px solid ' + TC.textStrong : '1px solid ' + TC.line,
              color: on ? '#fff' : TC.text,
              fontSize: 13, fontWeight: on ? 600 : 500, letterSpacing: '0.015em',
              display: 'inline-flex', alignItems: 'center', gap: 6, whiteSpace: 'nowrap',
              transition: 'all 120ms cubic-bezier(0.2,0,0,1)',
            }}>{it.label}</button>
          );
        })}
      </div>
    </div>
  );
}

// ── 검색바
function SearchBar({ value, onChange, placeholder = '지점명·지역으로 검색', onFocus }) {
  return (
    <div style={{
      padding: '10px 16px', background: '#fff',
      borderBottom: '0.5px solid ' + TC.lineSoft,
      fontFamily: FF,
    }}>
      <div style={{
        height: 40, padding: '0 12px',
        borderRadius: 10, background: TC.fillSubtle,
        display: 'flex', alignItems: 'center', gap: 8,
      }}>
        <Icon name="search" size={18} color={TC.textNeutral} stroke={2} />
        <input
          value={value}
          onFocus={onFocus}
          onChange={e => onChange(e.target.value)}
          placeholder={placeholder}
          style={{
            all: 'unset', flex: 1, fontSize: 14, fontWeight: 500,
            fontFamily: FF, letterSpacing: '0.015em', color: TC.textStrong,
          }}
        />
        {value && (
          <button onClick={() => onChange('')} style={{
            all: 'unset', cursor: 'pointer', display: 'flex',
            width: 18, height: 18, borderRadius: 999, background: TC.fillStrong,
            alignItems: 'center', justifyContent: 'center',
          }}><Icon name="x" size={12} color={TC.text} stroke={2.5} /></button>
        )}
      </div>
    </div>
  );
}

// ── 뷰 토글 (지도/리스트)
function ViewToggle({ view, onChange }) {
  return (
    <div style={{
      display: 'inline-flex', borderRadius: 999, background: TC.fillSubtle,
      padding: 3, fontFamily: FF,
    }}>
      {[
        { id: 'map', label: '지도', icon: 'map-pin' },
        { id: 'list', label: '리스트', icon: 'list' },
      ].map(it => {
        const on = view === it.id;
        return (
          <button key={it.id} onClick={() => onChange(it.id)} style={{
            all: 'unset', cursor: 'pointer',
            height: 32, padding: '0 12px',
            borderRadius: 999,
            background: on ? '#fff' : 'transparent',
            color: on ? TC.textStrong : TC.textNeutral,
            fontSize: 12, fontWeight: 600,
            display: 'inline-flex', alignItems: 'center', gap: 4,
            boxShadow: on ? '0 1px 2px rgba(0,0,0,0.06)' : 'none',
          }}>
            <Icon name={it.icon} size={14} stroke={2} />
            {it.label}
          </button>
        );
      })}
    </div>
  );
}

// ── 타운카 공식 뱃지
function OfficialBadge() {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 3,
      height: 20, padding: '0 7px', borderRadius: 6,
      background: TC.primarySubtle, color: TC.primaryPressed,
      fontSize: 11, fontWeight: 700, letterSpacing: '0.015em',
      fontFamily: FF,
    }}>
      <Icon name="badge-check" size={12} color={TC.primaryPressed} stroke={2.2} />
      타운카 공식
    </span>
  );
}

// ── 일반 뱃지
function MiniBadge({ children, tone = 'neutral' }) {
  const tones = {
    neutral: { bg: TC.fillSubtle, fg: TC.text },
    info:    { bg: 'rgba(0,138,237,0.10)', fg: '#0067BC' },
    accent:  { bg: 'rgba(255,87,134,0.10)', fg: '#C61C5A' },
    yellow:  { bg: 'rgba(245,185,0,0.14)', fg: '#8A6500' },
    discount:{ bg: 'rgba(228,31,16,0.10)', fg: '#B81000' },
  };
  const t = tones[tone] || tones.neutral;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', height: 20, padding: '0 7px',
      borderRadius: 5, background: t.bg, color: t.fg,
      fontSize: 11, fontWeight: 600, letterSpacing: '0.015em',
      fontFamily: FF, whiteSpace: 'nowrap',
    }}>{children}</span>
  );
}

// ── 파트너 카드 (리스트용)
function PartnerCard({ partner, brandLabel, onClick, onCall, onMap, active, index }) {
  const p = partner;
  return (
    <div onClick={onClick} style={{
      background: active ? 'rgba(11,181,59,0.04)' : '#fff',
      padding: '14px 16px',
      borderBottom: '0.5px solid ' + TC.lineSoft,
      cursor: 'pointer', position: 'relative',
      boxShadow: active ? `inset 3px 0 0 ${TC.primary}` : 'none',
      fontFamily: FF,
    }}
    >
      {/* head row */}
      <div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginBottom: 6 }}>
        {/* index pin */}
        {index != null && (
          <span style={{
            flexShrink: 0, width: 22, height: 22, borderRadius: 999,
            background: active ? TC.primary : TC.textStrong,
            color: '#fff',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            fontSize: 12, fontWeight: 700, marginTop: 1,
          }}>{index}</span>
        )}
        <div style={{ flex: 1, minWidth: 0 }}>
          {/* brand row */}
          {brandLabel && (
            <div style={{
              fontSize: 11, fontWeight: 600, color: TC.textNeutral,
              letterSpacing: '0.025em', marginBottom: 3,
            }}>{brandLabel}</div>
          )}
          {/* name */}
          <div style={{
            fontSize: 15, fontWeight: 700, color: TC.textStrong,
            letterSpacing: '-0.020em', lineHeight: '20px',
            display: 'flex', alignItems: 'center', gap: 6, flexWrap: 'wrap',
          }}>
            {p.name}
            {p.flagship && <MiniBadge tone="yellow">플래그십</MiniBadge>}
          </div>
        </div>
        <Icon name="chevron-right" size={18} color={TC.textAlt} />
      </div>

      {/* badges */}
      {(p.official || p.discount || (p.badges && p.badges.length)) && (
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4, marginBottom: 8, marginLeft: index != null ? 32 : 0 }}>
          {p.official && <OfficialBadge />}
          {p.discount && <MiniBadge tone="discount">제휴 할인</MiniBadge>}
          {p.badges && p.badges.map((b, i) => <MiniBadge key={i} tone="info">{b}</MiniBadge>)}
        </div>
      )}

      {/* address */}
      <div style={{ marginLeft: index != null ? 32 : 0 }}>
        <div style={{
          fontSize: 12.5, color: p.address ? TC.text : TC.textAlt,
          letterSpacing: '0.020em', lineHeight: '17px',
          display: 'flex', alignItems: 'center', gap: 4, minWidth: 0,
        }}>
          <Icon name="map-pin" size={12} color={TC.textNeutral} stroke={2} style={{ flexShrink: 0 }} />
          <span style={{
            flex: 1, minWidth: 0,
            whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
          }}>{p.address || (p.branchPhone ? '지점 내방 문의' : '주소 확인 중')}</span>
        </div>
        {p.note && (
          <div style={{
            marginTop: 3, fontSize: 11.5, color: TC.textAlt, letterSpacing: '0.025em',
          }}>* {p.note}</div>
        )}
      </div>
    </div>
  );
}

// ── 빈 상태
function EmptyState({ title, subtitle, icon = 'search-x' }) {
  return (
    <div style={{
      padding: '48px 24px', display: 'flex', flexDirection: 'column',
      alignItems: 'center', gap: 8, fontFamily: FF,
    }}>
      <div style={{
        width: 56, height: 56, borderRadius: 999, background: TC.fillSubtle,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>
        <Icon name={icon} size={26} color={TC.textNeutral} stroke={1.8} />
      </div>
      <div style={{ fontSize: 15, fontWeight: 600, color: TC.textStrong, marginTop: 4 }}>{title}</div>
      {subtitle && <div style={{ fontSize: 13, color: TC.textNeutral, textAlign: 'center', lineHeight: '18px' }}>{subtitle}</div>}
    </div>
  );
}

// ── 토스트
function Toast({ message, visible }) {
  return (
    <div style={{
      position: 'absolute', bottom: visible ? 100 : 60, left: '50%',
      transform: 'translateX(-50%)',
      background: 'rgba(0,0,0,0.84)', color: '#fff',
      padding: '11px 18px', borderRadius: 999,
      fontSize: 13, fontWeight: 500, letterSpacing: '0.015em',
      fontFamily: FF, whiteSpace: 'nowrap',
      opacity: visible ? 1 : 0,
      pointerEvents: 'none',
      transition: 'all 240ms cubic-bezier(0.2,0,0,1)',
      zIndex: 200,
    }}>{message}</div>
  );
}

// ── 네이버 지도 URL
function naverMapUrl(partner) {
  const q = partner.address || partner.name;
  return 'https://map.naver.com/p/search/' + encodeURIComponent(q);
}

// ── 전화 URL
function telUrl(phone) {
  return 'tel:' + String(phone || '').replace(/[^0-9+]/g, '');
}

Object.assign(window, {
  TC, FF, Icon, useDragScroll, PageHeader, CategoryTabs, SubChips, SearchBar, ViewToggle,
  OfficialBadge, MiniBadge, PartnerCard: React.memo(PartnerCard), EmptyState, Toast,
  naverMapUrl, telUrl,
});
