const { useState: useStateWatch, useEffect: useEffectWatch, useMemo: useMemoWatch } = React;
const WATCH_CONTACT_QR_URL = '/assets/wechat-qr.jpg';
const WATCH_CONTACT_WECHAT_ID = 'urrent';

function normalizeWatchGalleryLabel(item, index) {
  const raw = item?.label || item?.title || item?.name || item?.alt || item?.comment || '';
  const text = String(raw).trim();
  if (!text) return index === 0 ? '物件外观' : `物件图片 ${index + 1}`;
  if (text.includes('外観')) return '物件外观';
  if (text.includes('周辺')) return '周边环境';
  return text.length > 18 ? text.slice(0, 18) + '…' : text;
}

function WatchScreen({ onOpenRoom }) {
  const [session, setSession] = useStateWatch(getWatchSession());
  const [sessionLoading, setSessionLoading] = useStateWatch(Boolean(getWatchSession()?.token));
  const [authOpen, setAuthOpen] = useStateWatch(false);
  const [authStep, setAuthStep] = useStateWatch('email');
  const [email, setEmail] = useStateWatch('');
  const [code, setCode] = useStateWatch('');
  const [debugCode, setDebugCode] = useStateWatch('');
  const [authError, setAuthError] = useStateWatch('');
  const [authLoading, setAuthLoading] = useStateWatch(false);
  const [contactOpen, setContactOpen] = useStateWatch(false);
  const [saveLabel, setSaveLabel] = useStateWatch('保存二维码');

  const [subscriptions, setSubscriptions] = useStateWatch([]);
  const [subscriptionsLoading, setSubscriptionsLoading] = useStateWatch(false);
  const [watchDetailKey, setWatchDetailKey] = useStateWatch(null);

  const [locSheetOpen, setLocSheetOpen] = useStateWatch(false);
  const [rentSheetOpen, setRentSheetOpen] = useStateWatch(false);
  const [districtSheetOpen, setDistrictSheetOpen] = useStateWatch(false);
  const [locationFilter, setLocationFilter] = useStateWatch({ regions: ['tokyo'], areas: [] });
  const [selectedDistricts, setSelectedDistricts] = useStateWatch([]);
  const [rent, setRent] = useStateWatch({ min: 0, max: MAX_RENT });
  const [areasByRegion, setAreasByRegion] = useStateWatch({});
  const [catalogLoading, setCatalogLoading] = useStateWatch(false);
  const [catalogError, setCatalogError] = useStateWatch('');
  const [catalogProperties, setCatalogProperties] = useStateWatch([]);

  const selectedKeys = locationFilter.regions;
  const selectedAreaKeys = locationFilter.areas;
  const watchAccessEnabled = Boolean(session?.user?.watchAccessEnabled);

  const updateSessionUser = (nextUser) => {
    setSession((current) => {
      if (!current) return current;
      const nextSession = { ...current, user: { ...current.user, ...nextUser } };
      setWatchSession(nextSession);
      return nextSession;
    });
  };

  const ensureAreas = async (regionKey) => {
    if (!regionKey) return;
    const current = areasByRegion[regionKey];
    if (current?.loading || current?.loaded) return;

    setAreasByRegion((prev) => ({
      ...prev,
      [regionKey]: {
        data: prev[regionKey]?.data || [],
        loading: true,
        loaded: false,
        error: null,
      },
    }));

    try {
      const res = await apiFetch('/api/v1/areas?regionKey=' + encodeURIComponent(regionKey));
      const data = Array.isArray(res) ? res : (res.data || res.areas || res.items || []);
      setAreasByRegion((prev) => ({
        ...prev,
        [regionKey]: { data, loading: false, loaded: true, error: null },
      }));
    } catch (error) {
      setAreasByRegion((prev) => ({
        ...prev,
        [regionKey]: {
          data: prev[regionKey]?.data || [],
          loading: false,
          loaded: false,
          error: error.message || '区域加载失败',
        },
      }));
    }
  };

  useEffectWatch(() => {
    selectedKeys.forEach(ensureAreas);
  }, [selectedKeys.join(',')]);

  useEffectWatch(() => {
    const existing = getWatchSession();
    if (!existing?.token) {
      setSessionLoading(false);
      return;
    }
    subscribeApiFetch('/me', { token: existing.token })
      .then((res) => {
        const nextSession = { token: existing.token, user: res.user };
        setSession(nextSession);
        setWatchSession(nextSession);
      })
      .catch(() => {
        clearWatchSession();
        setSession(null);
      })
      .finally(() => setSessionLoading(false));
  }, []);

  useEffectWatch(() => {
    if (!session?.token || !watchAccessEnabled) return;
    refreshSubscriptions();
  }, [session?.token, watchAccessEnabled]);

  useEffectWatch(() => {
    if (!session?.token || !watchAccessEnabled) return;
    loadCatalogProperties();
  }, [session?.token, watchAccessEnabled, selectedKeys.join(','), selectedAreaKeys.join(','), rent.min, rent.max]);

  useEffectWatch(() => {
    if (!session?.token || watchAccessEnabled) return;
    setSubscriptions([]);
    setCatalogProperties([]);
    setWatchDetailKey(null);
  }, [session?.token, watchAccessEnabled]);

  async function refreshSubscriptions() {
    if (!session?.token) return;
    setSubscriptionsLoading(true);
    try {
      const res = await subscribeApiFetch('/subscriptions', { token: session.token });
      setSubscriptions(res.subscriptions || []);
    } catch (error) {
      if (error.message === 'watch_access_disabled') {
        updateSessionUser({ watchAccessEnabled: false });
        setSubscriptions([]);
        return;
      }
      console.error('load subscriptions failed', error);
    } finally {
      setSubscriptionsLoading(false);
    }
  }

  async function loadCatalogProperties() {
    if (!session?.token) return;
    if (selectedKeys.length === 0) {
      setCatalogProperties([]);
      return;
    }

    setCatalogLoading(true);
    setCatalogError('');
    try {
      const merged = [];
      const seen = new Set();
      for (const regionKey of selectedKeys) {
        const res = await subscribeApiFetch('/catalog/properties?regionKey=' + encodeURIComponent(regionKey), {
          token: session.token,
        });
        const list = Array.isArray(res) ? res : (res.data || res.items || []);
        for (const item of list) {
          const key = item.propertyKey || item.propertyId || item.id;
          if (seen.has(key)) continue;
          seen.add(key);
          merged.push(item);
        }
      }
      setCatalogProperties(merged);
    } catch (error) {
      if (error.message === 'watch_access_disabled') {
        updateSessionUser({ watchAccessEnabled: false });
        setCatalogProperties([]);
        setCatalogError('');
        return;
      }
      setCatalogError(error.message || '加载全部物业失败');
      setCatalogProperties([]);
    } finally {
      setCatalogLoading(false);
    }
  }

  async function handleRequestCode() {
    setAuthLoading(true);
    setAuthError('');
    try {
      const res = await subscribeApiFetch('/auth/request-code', {
        method: 'POST',
        body: { email },
      });
      setAuthStep('code');
      setDebugCode(res.debugCode || '');
    } catch (error) {
      setAuthError(error.message === 'invalid_email' ? '请输入正确的邮箱地址' : '验证码发送失败，请稍后重试');
    } finally {
      setAuthLoading(false);
    }
  }

  async function handleVerifyCode() {
    setAuthLoading(true);
    setAuthError('');
    try {
      const res = await subscribeApiFetch('/auth/verify-code', {
        method: 'POST',
        body: { email, code },
      });
      const nextSession = { token: res.token, user: res.user };
      setSession(nextSession);
      setWatchSession(nextSession);
      setAuthOpen(false);
      setAuthStep('email');
      setCode('');
      setDebugCode('');
      setWatchDetailKey(null);
    } catch (error) {
      setAuthError(error.message === 'invalid_code' ? '验证码不正确' : '验证失败，请稍后重试');
    } finally {
      setAuthLoading(false);
    }
  }

  function handleLogout() {
    clearWatchSession();
    setSession(null);
    setSubscriptions([]);
  }

  async function handleDeleteSubscription(propertyKey) {
    if (!session?.token) return;
    try {
      await subscribeApiFetch('/subscriptions/' + encodeURIComponent(propertyKey), {
        method: 'DELETE',
        token: session.token,
      });
      refreshSubscriptions();
    } catch (error) {
      if (error.message === 'watch_access_disabled') {
        updateSessionUser({ watchAccessEnabled: false });
        return;
      }
      console.error('delete subscription failed', error);
    }
  }

  const saveQrCode = async () => {
    try {
      const res = await fetch(WATCH_CONTACT_QR_URL);
      const blob = await res.blob();
      const objectUrl = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = objectUrl;
      a.download = 'urrent-wechat-qr.jpg';
      document.body.appendChild(a);
      a.click();
      a.remove();
      window.setTimeout(() => URL.revokeObjectURL(objectUrl), 1500);
      setSaveLabel('已开始保存');
      window.setTimeout(() => setSaveLabel('保存二维码'), 1800);
    } catch (error) {
      console.error('save qr failed', error);
      setSaveLabel('保存失败，请重试');
      window.setTimeout(() => setSaveLabel('保存二维码'), 2200);
    }
  };

  const areaLabelOf = (areaKey) => {
    const regionKey = areaKey.split('__')[0];
    const area = areasByRegion[regionKey]?.data?.find((item) => item.areaKey === areaKey);
    return area?.name || areaKey;
  };
  const labelOf = (key) => {
    for (const group of REGIONS) {
      const match = group.prefs.find((pref) => pref.key === key);
      if (match) return match.label;
    }
    return key;
  };

  const locLabel = selectedAreaKeys.length > 0
    ? (selectedAreaKeys.length === 1 ? areaLabelOf(selectedAreaKeys[0]) : `${areaLabelOf(selectedAreaKeys[0])} 等${selectedAreaKeys.length}个片区`)
    : (selectedKeys.length === 1 ? labelOf(selectedKeys[0]) : '位置');

  const rentLabel = (rent.min === 0 && rent.max === MAX_RENT)
    ? '租金'
    : rent.max >= MAX_RENT
      ? `¥${manYen(rent.min)}〜`
      : rent.min === 0
        ? `〜¥${manYen(rent.max)}`
        : `¥${manYen(rent.min)}〜${manYen(rent.max)}`;
  const districtOptions = useMemoWatch(() => (
    selectedAreaKeys.length > 0
      ? buildDistrictOptions(
          catalogProperties,
          selectedAreaKeys,
          areasByRegion,
          (property) => property.districtName || property.skcs || ''
        )
      : []
  ), [catalogProperties, selectedAreaKeys, areasByRegion]);

  useEffectWatch(() => {
    const validDistricts = new Set(districtOptions.map((item) => item.key));
    setSelectedDistricts((prev) => {
      const next = prev.filter((item) => validDistricts.has(item));
      return next.length === prev.length ? prev : next;
    });
  }, [districtOptions]);

  const districtLabel = selectedDistricts.length > 0
    ? (selectedDistricts.length === 1 ? selectedDistricts[0] : `${selectedDistricts[0]} 等${selectedDistricts.length}个区域`)
    : '区域';

  const filteredCatalogProperties = useMemoWatch(() => {
    return catalogProperties.filter((property) => {
      const parsed = parseRentRange(property.detailRentText || property.rent);
      if (parsed.max < rent.min) return false;
      if (parsed.min > rent.max) return false;
      if (selectedAreaKeys.length > 0 && !selectedAreaKeys.includes(property.areaKey)) return false;
      if (selectedDistricts.length > 0 && !selectedDistricts.includes(normalizeDistrictName(property.districtName || property.skcs))) return false;
      return true;
    });
  }, [catalogProperties, rent.min, rent.max, selectedAreaKeys.join(','), selectedDistricts.join(',')]);

  if (sessionLoading) {
    return (
      <div style={watchStyles.loadingWrap}>
        <div style={watchStyles.loadingCard}>正在加载蹲房服务…</div>
      </div>
    );
  }

  return (
    <div style={watchStyles.shell}>
      {!session ? (
        <div style={watchStyles.heroWrap}>
          <div style={watchStyles.heroCard}>
            <div style={watchStyles.heroRing}>
              <div style={watchStyles.heroIcon}><Icon.Bell size={28} color="#C6572B"/></div>
            </div>
            <div style={watchStyles.heroTitle}>蹲房</div>
            <div style={watchStyles.heroDesc}>
              绑定邮箱后，订阅你关心的物业名。<br/>
              一旦有房源重新出现，我们会第一时间邮件通知你。
            </div>
            <div style={watchStyles.heroFeatures}>
              {[
                { t: '物业级订阅', d: '一个账号可同时蹲多个物业名' },
                { t: '邮件提醒', d: '新房源出现后直接邮件通知' },
                { t: '直达房间', d: '邮件点击可直达对应房间信息' },
              ].map((item) => (
                <div key={item.t} style={watchStyles.heroFeature}>
                  <div style={watchStyles.heroDot}/>
                  <div>
                    <div style={watchStyles.heroFeatureTitle}>{item.t}</div>
                    <div style={watchStyles.heroFeatureDesc}>{item.d}</div>
                  </div>
                </div>
              ))}
            </div>
            <button style={{ ...watchStyles.primaryButton, ...watchStyles.heroCtaButton }} onClick={() => setAuthOpen(true)}>
              开启蹲房
            </button>
          </div>
        </div>
      ) : !watchAccessEnabled ? (
        <div style={watchStyles.content}>
          <div style={watchStyles.summaryCard}>
            <div>
              <div style={watchStyles.summaryTitle}>我的蹲房</div>
              <div style={watchStyles.summaryEmail}>
                <Icon.Mail size={13} color="#8A7F72"/>
                <span>{session.user.email}</span>
              </div>
            </div>
            <button style={watchStyles.ghostButton} onClick={handleLogout}>退出</button>
          </div>

          <div style={watchStyles.pendingCard}>
            <div style={watchStyles.pendingRing}>
              <div style={watchStyles.pendingIcon}><Icon.Bell size={28} color="#C6572B"/></div>
            </div>
            <div style={watchStyles.pendingTitle}>蹲房待开通</div>
            <div style={watchStyles.pendingDesc}>请联系租房助理免费开启蹲房</div>
            <div style={watchStyles.pendingSub}>
              你的邮箱已经注册成功。<br/>
              联系客服后，我们会帮你开启蹲房权限。
            </div>
          </div>
        </div>
      ) : (
        <div style={watchStyles.content}>
          <div style={watchStyles.summaryCard}>
            <div>
              <div style={watchStyles.summaryTitle}>我的蹲房</div>
              <div style={watchStyles.summaryEmail}>
                <Icon.Mail size={13} color="#8A7F72"/>
                <span>{session.user.email}</span>
              </div>
            </div>
            <button style={watchStyles.ghostButton} onClick={handleLogout}>退出</button>
          </div>

          <div style={watchStyles.sectionCard}>
            <div style={watchStyles.sectionHead}>
              <div style={watchStyles.sectionTitle}>订阅中的物业</div>
              <div style={watchStyles.sectionSub}>{subscriptions.length} 个订阅</div>
            </div>
            {subscriptionsLoading ? (
              <div style={watchStyles.emptyHint}>正在加载订阅列表…</div>
            ) : subscriptions.length === 0 ? (
              <div style={watchStyles.emptyHint}>还没有订阅任何物业，下面可以直接新增蹲房。</div>
            ) : (
              <div style={watchStyles.subscriptionList}>
                {subscriptions.map((item) => (
                  <div key={item.propertyKey} style={watchStyles.subscriptionRow}>
                    <button style={watchStyles.subscriptionMain} onClick={() => setWatchDetailKey(item.propertyKey)}>
                      <div style={watchStyles.subscriptionName}>{item.propertyName}</div>
                      <div style={watchStyles.subscriptionMeta}>
                        {item.regionName || '—'} · {item.districtName || item.areaName || '—'}
                      </div>
                    </button>
                    <div style={watchStyles.subscriptionRight}>
                      {(item.newListingCount || 0) > 0 && (
                        <div style={watchStyles.newBadge}>新增蹲房 {item.newListingCount}</div>
                      )}
                      <button
                        style={watchStyles.deleteBtn}
                        onClick={() => handleDeleteSubscription(item.propertyKey)}
                        aria-label="delete subscription"
                      >
                        <Icon.Trash size={14} color="#9A4E34"/>
                      </button>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>

          <div style={watchStyles.sectionCard}>
            <div style={watchStyles.sectionHead}>
              <div>
                <div style={watchStyles.sectionTitle}>新增蹲房</div>
                <div style={watchStyles.sectionSub}>显示该地区全部物业，选中后即可查看并订阅</div>
              </div>
            </div>

            <div style={watchStyles.filterRow}>
              <button style={watchStyles.filterPill} onClick={() => setLocSheetOpen(true)}>
                <Icon.Location size={13} color="#1A1A1A"/>
                <span>{locLabel}</span>
                <Icon.Chevron size={11} color="#1A1A1A"/>
              </button>
              <button style={watchStyles.filterPill} onClick={() => setRentSheetOpen(true)}>
                <Icon.Yen size={13} color="#1A1A1A"/>
                <span>{rentLabel}</span>
                <Icon.Chevron size={11} color="#1A1A1A"/>
              </button>
              {selectedAreaKeys.length > 0 && districtOptions.length > 0 && (
                <button style={watchStyles.filterPill} onClick={() => setDistrictSheetOpen(true)}>
                  <Icon.Location size={13} color="#1A1A1A"/>
                  <span>{districtLabel}</span>
                  <Icon.Chevron size={11} color="#1A1A1A"/>
                </button>
              )}
            </div>

            {catalogLoading ? (
              <div style={watchStyles.emptyHint}>正在加载全部物业…</div>
            ) : catalogError ? (
              <div style={watchStyles.errorHint}>{catalogError}</div>
            ) : filteredCatalogProperties.length === 0 ? (
              <div style={watchStyles.emptyHint}>当前筛选条件下没有找到物业。</div>
            ) : (
              <div style={watchStyles.catalogList}>
                {filteredCatalogProperties.map((property) => {
                  const subscribed = subscriptions.some((item) => item.propertyKey === property.propertyKey);
                  const thumbUrl = resolveImg(property.propertyImageLocalUrl || property.propertyImageRemoteUrl || property.image);
                  return (
                    <button
                      key={property.propertyKey}
                      style={watchStyles.catalogItem}
                      onClick={() => setWatchDetailKey(property.propertyKey)}
                    >
                      <div style={watchStyles.catalogThumb}>
                        {thumbUrl ? (
                          <img src={thumbUrl} alt={property.name} style={watchStyles.catalogThumbImg}/>
                        ) : (
                          <BuildingPlaceholder seed={(property.name || '').length * 5} width={72} height={72}/>
                        )}
                      </div>
                      <div style={watchStyles.catalogBody}>
                        <div style={watchStyles.catalogName}>{property.name}</div>
                        <div style={watchStyles.catalogMeta}>{property.address || property.skcs || property.districtName || '—'}</div>
                        <div style={watchStyles.catalogRent}>{property.detailRentText || property.rent || '—'}</div>
                      </div>
                      {subscribed && <div style={watchStyles.miniBadge}>已订阅</div>}
                    </button>
                  );
                })}
              </div>
            )}
          </div>
        </div>
      )}

      <LocationSheet
        open={locSheetOpen}
        onClose={() => setLocSheetOpen(false)}
        selectedRegions={selectedKeys}
        selectedAreas={selectedAreaKeys}
        onChange={setLocationFilter}
        areasByRegion={areasByRegion}
        ensureAreas={ensureAreas}
        countMode="properties"
      />
      <RentSheet open={rentSheetOpen} onClose={() => setRentSheetOpen(false)} value={rent} onChange={setRent}/>
      <DistrictSheet
        open={districtSheetOpen}
        onClose={() => setDistrictSheetOpen(false)}
        options={districtOptions}
        selectedDistricts={selectedDistricts}
        onChange={setSelectedDistricts}
        countMode="properties"
      />

      {authOpen && (
        <div style={watchStyles.modalBackdrop} onClick={() => setAuthOpen(false)}>
          <div style={watchStyles.modalCard} onClick={(event) => event.stopPropagation()}>
            <button style={watchStyles.modalClose} onClick={() => setAuthOpen(false)}>
              <Icon.Close size={18} color="#1A1A1A"/>
            </button>
            <div style={watchStyles.modalTitle}>开启蹲房</div>
            <div style={watchStyles.modalDesc}>请先绑定通知邮箱，并完成邮箱验证码验证。</div>
            {authStep === 'email' ? (
              <>
                <input
                  value={email}
                  onChange={(event) => setEmail(event.target.value)}
                  placeholder="请输入邮箱地址"
                  style={watchStyles.input}
                />
                {authError && <div style={watchStyles.errorText}>{authError}</div>}
                <button style={watchStyles.primaryButton} onClick={handleRequestCode} disabled={authLoading}>
                  {authLoading ? '发送中…' : '发送验证码'}
                </button>
              </>
            ) : (
              <>
                <div style={watchStyles.modalSubText}>验证码已发送至 {email}</div>
                <input
                  value={code}
                  onChange={(event) => setCode(event.target.value)}
                  placeholder="请输入 6 位验证码"
                  style={watchStyles.input}
                />
                {debugCode && <div style={watchStyles.devCode}>测试验证码：{debugCode}</div>}
                {authError && <div style={watchStyles.errorText}>{authError}</div>}
                <button style={watchStyles.primaryButton} onClick={handleVerifyCode} disabled={authLoading}>
                  {authLoading ? '验证中…' : '完成验证并注册'}
                </button>
              </>
            )}
          </div>
        </div>
      )}

      {session && !watchAccessEnabled && (
        <div style={watchStyles.pendingBar}>
          <button style={{ ...watchStyles.primaryButton, width: '100%' }} onClick={() => setContactOpen(true)}>
            点击联系
          </button>
        </div>
      )}

      {contactOpen && (
        <div style={watchStyles.modalBackdrop} onClick={() => setContactOpen(false)}>
          <div style={watchStyles.contactCard} onClick={(event) => event.stopPropagation()}>
            <button style={watchStyles.modalClose} onClick={() => setContactOpen(false)}>
              <Icon.Close size={18} color="#1A1A1A"/>
            </button>
            <div style={watchStyles.contactTitle}>请加微信客服</div>
            <div style={watchStyles.contactWechat}>微信ID {WATCH_CONTACT_WECHAT_ID}</div>
            <div style={watchStyles.contactQrWrap}>
              <img src={WATCH_CONTACT_QR_URL} alt="微信客服二维码" style={watchStyles.contactQrImg}/>
            </div>
            <div style={watchStyles.contactHint}>长按或保存二维码后，使用微信扫码添加客服。</div>
            <button style={{ ...watchStyles.primaryButton, width: '100%', marginTop: 14 }} onClick={saveQrCode}>
              {saveLabel}
            </button>
          </div>
        </div>
      )}

      {watchDetailKey && (
        <WatchPropertyDetail
          propertyKey={watchDetailKey}
          token={session?.token}
          subscriptions={subscriptions}
          onBack={() => setWatchDetailKey(null)}
          onSubscribed={refreshSubscriptions}
          onOpenRoom={onOpenRoom}
        />
      )}
    </div>
  );
}

function WatchPropertyDetail({ propertyKey, token, subscriptions, onBack, onSubscribed, onOpenRoom }) {
  const [loading, setLoading] = useStateWatch(true);
  const [error, setError] = useStateWatch('');
  const [data, setData] = useStateWatch(null);
  const [tab, setTab] = useStateWatch('info');
  const [galleryIndex, setGalleryIndex] = useStateWatch(0);
  const [subscribing, setSubscribing] = useStateWatch(false);

  const subscribed = subscriptions.some((item) => item.propertyKey === propertyKey);

  useEffectWatch(() => {
    let cancelled = false;
    setLoading(true);
    setError('');
    subscribeApiFetch('/property/' + encodeURIComponent(propertyKey) + '?markRead=1', { token })
      .then((res) => {
        if (!cancelled) setData(res);
      })
      .catch((err) => {
        if (!cancelled) setError(err.message || '加载物业信息失败');
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => { cancelled = true; };
  }, [propertyKey, token]);

  const property = data?.property || {};
  const activeProperty = data?.activeProperty || {};
  const mergedProperty = useMemoWatch(() => {
    const featureTags = Array.from(new Set([...(property.featureTags || []), ...(activeProperty.featureTags || [])]));
    const facilityTags = Array.from(new Set([...(property.facilityTags || []), ...(activeProperty.facilityTags || [])]));
    const galleryImages = [
      ...(property.galleryImages || []),
      ...(activeProperty.galleryImages || []),
    ];

    return {
      ...property,
      ...activeProperty,
      galleryImages,
      featureTags,
      facilityTags,
      access: activeProperty.access?.length ? activeProperty.access : (property.access || []),
      accessText: activeProperty.accessText || property.accessText || '',
      detailTransportText: activeProperty.detailTransportText || property.detailTransportText || activeProperty.accessText || property.accessText || '',
      propertyImageLocalUrl: activeProperty.propertyImageLocalUrl || property.propertyImageLocalUrl,
      propertyImageRemoteUrl: activeProperty.propertyImageRemoteUrl || property.propertyImageRemoteUrl,
      image: activeProperty.image || property.image,
      address: activeProperty.address || property.address || '',
      householdCount: activeProperty.householdCount || property.householdCount || '',
      parkingInfoText: activeProperty.parkingInfoText || property.parkingInfoText || '',
      floorPlanText: activeProperty.floorPlanText || property.floorPlanText || '',
      detailRentText: activeProperty.detailRentText || property.detailRentText || property.rent || '',
    };
  }, [property, activeProperty]);
  const latestListedRoom = data?.latestListedRoom || null;
  const rooms = activeProperty.rooms || [];
  const gallery = useMemoWatch(() => {
    const images = [];
    const seen = new Set();
    const pushImage = (url, label) => {
      const resolved = resolveImg(url);
      if (!resolved || seen.has(resolved)) return;
      seen.add(resolved);
      images.push({ url: resolved, label });
    };
    (mergedProperty.galleryImages || []).forEach((item, index) => {
      pushImage(item.localUrl || item.url || item.remoteUrl, normalizeWatchGalleryLabel(item, index));
    });
    pushImage(mergedProperty.propertyImageLocalUrl || mergedProperty.propertyImageRemoteUrl || mergedProperty.image, '物件外观');
    return images;
  }, [propertyKey, mergedProperty]);

  async function handleSubscribe() {
    if (subscribed || !token) return;
    setSubscribing(true);
    try {
      await subscribeApiFetch('/subscriptions', {
        method: 'POST',
        token,
        body: { propertyKey },
      });
      await onSubscribed();
    } catch (error) {
      if (error.message === 'watch_access_disabled') {
        onSubscribed && onSubscribed();
        return;
      }
      console.error('subscribe failed', error);
    } finally {
      setSubscribing(false);
    }
  }

  return (
    <div style={watchStyles.detailShell}>
      <div style={watchStyles.detailTopBar}>
        <button style={watchStyles.detailBackBtn} onClick={onBack}>
          <Icon.Chevron size={16} dir="left" color="#1A1A1A"/>
        </button>
          <div style={watchStyles.detailTopTitle}>
          <div style={watchStyles.detailTopMain}>物业详情</div>
          <div style={watchStyles.detailTopSub}>{mergedProperty.name || propertyKey}</div>
        </div>
      </div>

      <div style={watchStyles.detailScroll}>
        {loading ? (
          <div style={watchStyles.loadingWrap}><div style={watchStyles.loadingCard}>正在加载物业信息…</div></div>
        ) : error ? (
          <div style={watchStyles.loadingWrap}><div style={watchStyles.loadingCard}>{error}</div></div>
        ) : (
          <>
            <div style={watchStyles.galleryWrap}>
              <div style={watchStyles.galleryMain}>
                {gallery[galleryIndex] ? (
                  <img src={gallery[galleryIndex].url} alt={gallery[galleryIndex].label} style={watchStyles.galleryImg}/>
                ) : (
                  <div style={watchStyles.galleryEmpty}><BuildingPlaceholder seed={(mergedProperty.name || '').length * 9} width={260} height={200}/></div>
                )}
                {gallery[galleryIndex] && <div style={watchStyles.galleryBadge}>{gallery[galleryIndex].label}</div>}
              </div>
              {gallery.length > 1 && (
                <div style={watchStyles.galleryThumbRow}>
                  {gallery.map((item, index) => (
                    <button
                      key={item.url}
                      style={{ ...watchStyles.galleryThumb, borderColor: galleryIndex === index ? '#1A1A1A' : '#E4DFD6' }}
                      onClick={() => setGalleryIndex(index)}
                    >
                      <img src={item.url} alt={item.label} style={watchStyles.galleryThumbImg}/>
                    </button>
                  ))}
                </div>
              )}
            </div>

            <div style={watchStyles.detailBlock}>
              <div style={watchStyles.detailWard}>
                <Icon.Location size={11} color="#8A7F72"/>
                <span>{mergedProperty.skcs || mergedProperty.districtName || mergedProperty.areaName || '—'} · {mergedProperty.regionName || '—'}</span>
              </div>
              <div style={watchStyles.detailName}>{mergedProperty.name}</div>
              <div style={watchStyles.detailAddress}>{mergedProperty.address || '—'}</div>
            </div>

            <div style={watchStyles.tabRow}>
              <button style={{ ...watchStyles.tabBtn, ...(tab === 'info' ? watchStyles.tabBtnActive : null) }} onClick={() => setTab('info')}>房源信息</button>
              <button style={{ ...watchStyles.tabBtn, ...(tab === 'overview' ? watchStyles.tabBtnActive : null) }} onClick={() => setTab('overview')}>物业概况</button>
            </div>

            {tab === 'info' ? (
              <>
                <div style={watchStyles.sectionCard}>
                  <div style={watchStyles.infoGrid}>
                    <InfoStat label="最近一次下架" value={data.summary.latestDelistedAt ? formatDateTimeZh(data.summary.latestDelistedAt) : '未知'}/>
                    <InfoStat label="当前租金" value={data.summary.currentRentText || '—'}/>
                  </div>
                </div>

                {latestListedRoom && (
                  <div style={watchStyles.sectionCard}>
                    <div style={watchStyles.sectionTitle}>最近发现的新房间</div>
                    <button style={watchStyles.latestRoomCard} onClick={() => onOpenRoom && onOpenRoom(propertyKey, latestListedRoom.roomKey)}>
                      <div>
                        <div style={watchStyles.latestRoomName}>{latestListedRoom.roomName}</div>
                        <div style={watchStyles.latestRoomMeta}>
                          {latestListedRoom.rent || '—'} · {latestListedRoom.type || '—'} · {latestListedRoom.floorspace || '—'} · {latestListedRoom.floor || '—'}
                        </div>
                      </div>
                      <Icon.Chevron size={12} dir="right" color="#B0A695"/>
                    </button>
                  </div>
                )}

                {rooms.length > 0 && (
                  <div style={watchStyles.sectionCard}>
                    <div style={watchStyles.sectionTitle}>当前可见房间</div>
                    <div style={watchStyles.roomList}>
                      {rooms.map((room) => (
                        <button key={room.roomKey} style={watchStyles.roomRow} onClick={() => onOpenRoom && onOpenRoom(propertyKey, room.roomKey)}>
                          <div>
                            <div style={watchStyles.latestRoomName}>{room.name}</div>
                            <div style={watchStyles.latestRoomMeta}>{room.rent || '—'} · {room.type || '—'} · {room.floorspace || '—'} · {room.floor || '—'}</div>
                          </div>
                          <Icon.Chevron size={12} dir="right" color="#B0A695"/>
                        </button>
                      ))}
                    </div>
                  </div>
                )}
              </>
            ) : (
              <>
                <div style={watchStyles.sectionCard}>
                  <div style={watchStyles.infoGrid}>
                    <InfoStat label="平均租金" value={data.summary.averageRentText || '—'}/>
                    <InfoStat label="当前空房" value={`${data.summary.activeRoomCount || 0} 套`}/>
                    <InfoStat label="房型范围" value={mergedProperty.floorPlanText || '—'}/>
                    <InfoStat label="总户数" value={mergedProperty.householdCount ? `${mergedProperty.householdCount} 户` : '—'}/>
                  </div>
                </div>

                <div style={watchStyles.sectionCard}>
                  <div style={watchStyles.sectionTitle}>交通信息</div>
                  <div style={watchStyles.bodyText}>{mergedProperty.detailTransportText || mergedProperty.accessText || '—'}</div>
                </div>

                <div style={watchStyles.sectionCard}>
                  <div style={watchStyles.sectionTitle}>物业信息</div>
                  <div style={watchStyles.metaList}>
                    <MetaLine label="地址" value={mergedProperty.address || '—'}/>
                    <MetaLine label="区域" value={`${mergedProperty.areaName || '—'}（${mergedProperty.areaRange || '—'}）`}/>
                    <MetaLine label="租金范围" value={mergedProperty.detailRentText || mergedProperty.rent || '—'}/>
                    <MetaLine label="房型范围" value={mergedProperty.floorPlanText || '—'}/>
                    <MetaLine label="物件编号" value={propertyKey}/>
                  </div>
                </div>

                {(mergedProperty.featureTags || []).length > 0 && (
                  <div style={watchStyles.sectionCard}>
                    <div style={watchStyles.sectionTitle}>物件亮点</div>
                    <div style={watchStyles.tagWrap}>
                      {(mergedProperty.featureTags || []).map((tag) => <span key={tag} style={watchStyles.featureTag}>{tag}</span>)}
                    </div>
                  </div>
                )}

                {(mergedProperty.facilityTags || []).length > 0 && (
                  <div style={watchStyles.sectionCard}>
                    <div style={watchStyles.sectionTitle}>配套设备</div>
                    <div style={watchStyles.tagWrap}>
                      {(mergedProperty.facilityTags || []).map((tag) => <span key={tag} style={watchStyles.facilityTag}>{tag}</span>)}
                    </div>
                  </div>
                )}

                {mergedProperty.parkingInfoText && (
                  <div style={watchStyles.sectionCard}>
                    <div style={watchStyles.sectionTitle}>停车信息</div>
                    <div style={watchStyles.bodyText}>{mergedProperty.parkingInfoText}</div>
                  </div>
                )}
              </>
            )}
          </>
        )}
      </div>

      <div style={watchStyles.detailCtaBar}>
        <button style={{ ...watchStyles.primaryButton, ...watchStyles.ctaButton, width: '100%' }} onClick={handleSubscribe} disabled={subscribed || subscribing}>
          {subscribed ? (
            <>
              <span style={watchStyles.ctaIcon}><Icon.Bell size={15} color="#FFFFFF" fill={true}/></span>
              <span>已订阅该物业</span>
            </>
          ) : subscribing ? (
            <>
              <span style={watchStyles.ctaIcon}><Icon.Bell size={15} color="#FFFFFF"/></span>
              <span>订阅中…</span>
            </>
          ) : (
            <>
              <span style={watchStyles.ctaIcon}><Icon.Bell size={15} color="#FFFFFF"/></span>
              <span>立即订阅蹲房</span>
            </>
          )}
        </button>
        <div style={watchStyles.ctaSub}>有房源后我们会邮件通知您</div>
      </div>
    </div>
  );
}

function InfoStat({ label, value }) {
  return (
    <div style={watchStyles.infoCell}>
      <div style={watchStyles.infoLabel}>{label}</div>
      <div style={watchStyles.infoValue}>{value}</div>
    </div>
  );
}

function MetaLine({ label, value }) {
  return (
    <div style={watchStyles.metaRow}>
      <div style={watchStyles.metaLabel}>{label}</div>
      <div style={watchStyles.metaValue}>{value}</div>
    </div>
  );
}

const watchStyles = {
  shell: { flex: 1, display: 'flex', flexDirection: 'column' },
  loadingWrap: { padding: '32px 16px' },
  loadingCard: { background: '#FFFFFF', borderRadius: 18, border: '1px solid #EDE6D9', padding: '20px', textAlign: 'center', color: '#6B6258', fontSize: 14 },
  heroWrap: { flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '20px 20px 120px' },
  heroCard: { width: '100%', background: '#FFFFFF', borderRadius: 20, padding: '28px 22px 24px', border: '1px solid #EDE6D9', boxShadow: '0 2px 10px rgba(60, 50, 30, 0.04)' },
  heroRing: { width: 92, height: 92, margin: '0 auto 18px', borderRadius: 46, background: 'linear-gradient(135deg, #FBEFE6, #F4EADB)', display: 'flex', alignItems: 'center', justifyContent: 'center' },
  heroIcon: { width: 64, height: 64, borderRadius: 32, background: '#FFF8F1', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid #F4D9C5' },
  heroTitle: { fontSize: 24, fontWeight: 700, color: '#1A1A1A', textAlign: 'center' },
  heroDesc: { marginTop: 12, fontSize: 13, color: '#6B6258', lineHeight: 1.8, textAlign: 'center' },
  heroFeatures: { display: 'flex', flexDirection: 'column', gap: 12, marginTop: 18, marginBottom: 20, borderTop: '1px dashed #EDE6D9', borderBottom: '1px dashed #EDE6D9', padding: '16px 0' },
  heroFeature: { display: 'flex', gap: 10, alignItems: 'flex-start' },
  heroDot: { width: 6, height: 6, borderRadius: 3, background: '#C6572B', marginTop: 8 },
  heroFeatureTitle: { fontSize: 13, fontWeight: 600, color: '#1A1A1A' },
  heroFeatureDesc: { fontSize: 11, color: '#8A7F72', marginTop: 2 },
  primaryButton: { border: 'none', background: '#1A1A1A', color: '#FFFFFF', borderRadius: 14, padding: '15px 18px', fontSize: 15, fontWeight: 700, fontFamily: 'inherit', cursor: 'pointer' },
  heroCtaButton: { display: 'block', width: 'fit-content', minWidth: 168, margin: '0 auto' },
  ctaButton: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8 },
  ctaIcon: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center' },
  ghostButton: { border: '1px solid #E4DFD6', background: '#FFFFFF', color: '#1A1A1A', borderRadius: 999, padding: '10px 14px', fontSize: 12, fontWeight: 600, fontFamily: 'inherit', cursor: 'pointer' },
  content: { flex: 1, overflowY: 'auto', padding: '14px 14px 120px' },
  summaryCard: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', background: '#FFFFFF', borderRadius: 18, border: '1px solid #EDE6D9', padding: '16px 18px', marginBottom: 14 },
  summaryTitle: { fontSize: 18, fontWeight: 700, color: '#1A1A1A' },
  summaryEmail: { marginTop: 6, display: 'flex', alignItems: 'center', gap: 6, color: '#8A7F72', fontSize: 12, fontWeight: 500 },
  pendingCard: { background: '#FFFFFF', borderRadius: 20, border: '1px solid #EDE6D9', padding: '28px 22px 24px', textAlign: 'center', boxShadow: '0 2px 10px rgba(60, 50, 30, 0.04)' },
  pendingRing: { width: 92, height: 92, margin: '0 auto 18px', borderRadius: 46, background: 'linear-gradient(135deg, #FBEFE6, #F4EADB)', display: 'flex', alignItems: 'center', justifyContent: 'center' },
  pendingIcon: { width: 64, height: 64, borderRadius: 32, background: '#FFF8F1', display: 'flex', alignItems: 'center', justifyContent: 'center', border: '1px solid #F4D9C5' },
  pendingTitle: { fontSize: 22, fontWeight: 700, color: '#1A1A1A' },
  pendingDesc: { marginTop: 10, fontSize: 16, color: '#1A1A1A', lineHeight: 1.6, fontWeight: 600 },
  pendingSub: { marginTop: 10, fontSize: 13, color: '#6B6258', lineHeight: 1.8 },
  sectionCard: { background: '#FFFFFF', borderRadius: 18, border: '1px solid #EDE6D9', padding: '16px', marginBottom: 14 },
  sectionHead: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 10, marginBottom: 12 },
  sectionTitle: { fontSize: 15, fontWeight: 700, color: '#1A1A1A' },
  sectionSub: { fontSize: 11, color: '#8A7F72' },
  emptyHint: { fontSize: 13, color: '#8A7F72', lineHeight: 1.7, padding: '4px 2px' },
  errorHint: { fontSize: 13, color: '#C6572B', lineHeight: 1.7, padding: '4px 2px' },
  subscriptionList: { display: 'flex', flexDirection: 'column', gap: 10 },
  subscriptionRow: { display: 'flex', justifyContent: 'space-between', gap: 10, padding: '12px 0', borderTop: '1px dashed #F4EFE4' },
  subscriptionMain: { background: 'transparent', border: 'none', padding: 0, textAlign: 'left', flex: 1, cursor: 'pointer', fontFamily: 'inherit' },
  subscriptionName: { fontSize: 14, fontWeight: 700, color: '#1A1A1A' },
  subscriptionMeta: { fontSize: 11, color: '#8A7F72', marginTop: 4 },
  subscriptionRight: { display: 'flex', alignItems: 'center', gap: 8 },
  newBadge: { background: '#FFF1E8', color: '#A85D37', borderRadius: 999, padding: '6px 10px', fontSize: 11, fontWeight: 700 },
  deleteBtn: { width: 34, height: 34, borderRadius: 17, border: '1px solid #F1D7CB', background: '#FFF8F4', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' },
  filterRow: { display: 'flex', flexWrap: 'wrap', gap: 8, marginBottom: 12 },
  filterPill: { display: 'inline-flex', alignItems: 'center', gap: 6, padding: '9px 14px', borderRadius: 999, border: '1px solid #E4DFD6', background: '#FFFFFF', fontSize: 13, fontWeight: 500, fontFamily: 'inherit', cursor: 'pointer' },
  catalogList: { display: 'flex', flexDirection: 'column', gap: 10 },
  catalogItem: { display: 'flex', gap: 12, alignItems: 'center', padding: '12px', borderRadius: 16, border: '1px solid #EDE6D9', background: '#FFFCF8', cursor: 'pointer', textAlign: 'left', fontFamily: 'inherit', position: 'relative' },
  catalogThumb: { width: 72, height: 72, borderRadius: 12, overflow: 'hidden', background: '#F4EFE4', border: '1px solid #EDE6D9', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' },
  catalogThumbImg: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' },
  catalogBody: { flex: 1, minWidth: 0 },
  catalogName: { fontSize: 14, fontWeight: 700, color: '#1A1A1A', lineHeight: 1.4 },
  catalogMeta: { fontSize: 11, color: '#8A7F72', marginTop: 4, lineHeight: 1.5 },
  catalogRent: { fontSize: 12, color: '#C6572B', marginTop: 8, fontWeight: 700 },
  miniBadge: { position: 'absolute', top: 10, right: 10, background: '#1A1A1A', color: '#FFFFFF', borderRadius: 999, padding: '4px 8px', fontSize: 10, fontWeight: 700 },
  modalBackdrop: { position: 'fixed', inset: 0, zIndex: 140, background: 'rgba(20,18,14,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '20px 16px' },
  modalCard: { width: '100%', maxWidth: 360, background: '#FFFCF8', borderRadius: 22, border: '1px solid #EEDFD0', boxShadow: '0 20px 48px rgba(20,18,14,0.18)', padding: '24px 18px 18px', position: 'relative' },
  modalClose: { position: 'absolute', top: 14, right: 14, width: 34, height: 34, borderRadius: 17, border: 'none', background: '#F4EADB', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' },
  modalTitle: { fontSize: 22, fontWeight: 800, color: '#1A1A1A', lineHeight: 1.2 },
  modalDesc: { fontSize: 13, color: '#6B6258', lineHeight: 1.7, marginTop: 10, marginBottom: 14 },
  modalSubText: { fontSize: 12, color: '#8A7F72', marginBottom: 10 },
  contactCard: { width: '100%', maxWidth: 360, background: '#FFFCF8', borderRadius: 22, border: '1px solid #EEDFD0', boxShadow: '0 20px 48px rgba(20,18,14,0.18)', padding: '24px 18px 18px', position: 'relative' },
  contactTitle: { fontSize: 22, fontWeight: 800, color: '#1A1A1A', lineHeight: 1.2, textAlign: 'center' },
  contactWechat: { fontSize: 15, color: '#8A7F72', fontWeight: 600, marginTop: 10, textAlign: 'center' },
  contactQrWrap: { width: 220, maxWidth: '100%', margin: '18px auto 0', padding: 10, borderRadius: 20, background: '#FFFFFF', border: '1px solid #EFE3D5' },
  contactQrImg: { width: '100%', height: 'auto', display: 'block', borderRadius: 14 },
  contactHint: { marginTop: 12, fontSize: 12, color: '#6B6258', lineHeight: 1.7, textAlign: 'center' },
  input: { width: '100%', borderRadius: 14, border: '1px solid #E4DFD6', background: '#FFFFFF', padding: '14px 16px', fontSize: 15, outline: 'none', marginBottom: 12, fontFamily: 'inherit' },
  errorText: { fontSize: 12, color: '#C6572B', marginBottom: 12 },
  devCode: { fontSize: 12, color: '#8A7F72', marginBottom: 12 },
  detailShell: { position: 'fixed', inset: 0, background: '#FAF8F5', zIndex: 130, display: 'flex', flexDirection: 'column' },
  detailTopBar: { padding: 'calc(12px + env(safe-area-inset-top, 0px)) 14px 10px', display: 'flex', alignItems: 'center', gap: 10, background: '#FAF8F5', borderBottom: '1px solid #EDE6D9' },
  detailBackBtn: { width: 36, height: 36, borderRadius: 18, border: '1px solid #EDE6D9', background: '#FFFFFF', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', flexShrink: 0 },
  detailTopTitle: { flex: 1, minWidth: 0 },
  detailTopMain: { fontSize: 14, fontWeight: 600, color: '#1A1A1A' },
  detailTopSub: { fontSize: 11, color: '#8A7F72', marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' },
  detailScroll: { flex: 1, overflowY: 'auto', paddingBottom: 'calc(120px + env(safe-area-inset-bottom, 0px))' },
  galleryWrap: { background: '#FFFFFF', padding: '12px 14px 14px' },
  galleryMain: { width: '100%', aspectRatio: '4 / 3', borderRadius: 14, overflow: 'hidden', background: '#F4EFE4', position: 'relative' },
  galleryImg: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' },
  galleryEmpty: { width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' },
  galleryBadge: { position: 'absolute', top: 10, left: 10, padding: '4px 10px', borderRadius: 999, background: 'rgba(26,26,26,0.72)', color: '#FFFFFF', fontSize: 11, fontWeight: 500 },
  galleryThumbRow: { display: 'flex', gap: 8, marginTop: 10 },
  galleryThumb: { flex: '0 0 68px', height: 52, borderRadius: 8, border: '2px solid #E4DFD6', overflow: 'hidden', padding: 0, background: '#F4EFE4', cursor: 'pointer' },
  galleryThumbImg: { width: '100%', height: '100%', objectFit: 'cover', display: 'block' },
  detailBlock: { padding: '16px 18px 14px', background: '#FFFFFF', borderTop: '1px solid #EDE6D9' },
  detailWard: { display: 'flex', alignItems: 'center', gap: 4, fontSize: 11, color: '#8A7F72', fontWeight: 500, marginBottom: 6 },
  detailName: { fontSize: 19, fontWeight: 700, color: '#1A1A1A', lineHeight: 1.3 },
  detailAddress: { marginTop: 10, fontSize: 12, color: '#6B6258', lineHeight: 1.6 },
  tabRow: { display: 'flex', gap: 8, padding: '14px 14px 0' },
  tabBtn: { flex: 1, padding: '11px 12px', borderRadius: 999, border: '1px solid #E4DFD6', background: '#FFFFFF', color: '#6B6258', fontSize: 13, fontWeight: 600, fontFamily: 'inherit', cursor: 'pointer' },
  tabBtnActive: { background: '#1A1A1A', color: '#FFFFFF', borderColor: '#1A1A1A' },
  infoGrid: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 },
  infoCell: { background: '#FAF6EE', borderRadius: 14, padding: '14px 16px' },
  infoLabel: { fontSize: 11, color: '#8A7F72', fontWeight: 600 },
  infoValue: { fontSize: 15, color: '#1A1A1A', fontWeight: 700, lineHeight: 1.5, marginTop: 6 },
  latestRoomCard: { width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, border: '1px solid #EDE6D9', background: '#FFFCF8', borderRadius: 16, padding: '14px 16px', cursor: 'pointer', fontFamily: 'inherit', textAlign: 'left' },
  latestRoomName: { fontSize: 14, fontWeight: 700, color: '#1A1A1A' },
  latestRoomMeta: { fontSize: 11, color: '#8A7F72', marginTop: 4, lineHeight: 1.6 },
  roomList: { display: 'flex', flexDirection: 'column', gap: 10 },
  roomRow: { width: '100%', display: 'flex', justifyContent: 'space-between', gap: 10, border: '1px solid #EDE6D9', background: '#FFFCF8', borderRadius: 16, padding: '14px 16px', cursor: 'pointer', fontFamily: 'inherit', textAlign: 'left' },
  bodyText: { fontSize: 12, color: '#1A1A1A', lineHeight: 1.8, whiteSpace: 'pre-wrap' },
  metaList: { display: 'flex', flexDirection: 'column' },
  metaRow: { display: 'flex', gap: 12, padding: '10px 0', borderBottom: '1px dashed #F4EFE4' },
  metaLabel: { width: 64, flexShrink: 0, fontSize: 11, color: '#8A7F72', fontWeight: 600 },
  metaValue: { flex: 1, fontSize: 12, color: '#1A1A1A', lineHeight: 1.7 },
  tagWrap: { display: 'flex', flexWrap: 'wrap', gap: 8 },
  featureTag: { padding: '8px 12px', borderRadius: 999, background: '#FFF1E8', color: '#A85D37', fontSize: 11, fontWeight: 600 },
  facilityTag: { padding: '8px 12px', borderRadius: 999, background: '#F4EFE4', color: '#6B6258', fontSize: 11, fontWeight: 600 },
  detailCtaBar: { position: 'fixed', bottom: 0, left: 0, right: 0, zIndex: 135, background: 'rgba(250,248,245,0.95)', borderTop: '1px solid #EDE6D9', padding: '12px 16px calc(16px + env(safe-area-inset-bottom, 0px))' },
  ctaSub: { marginTop: 8, fontSize: 11, color: '#8A7F72', textAlign: 'center' },
  pendingBar: { position: 'fixed', bottom: 0, left: 0, right: 0, zIndex: 120, background: 'rgba(250,248,245,0.95)', borderTop: '1px solid #EDE6D9', padding: '12px 16px calc(16px + env(safe-area-inset-bottom, 0px))' },
};

Object.assign(window, { WatchScreen });
