import { useEffect, useMemo, useRef, useState } from 'react';
import { View, Text, Image, Input } from '@tarojs/components';
import Taro, { useDidShow, usePullDownRefresh, useShareAppMessage, useShareTimeline } from '@tarojs/taro';
import PageShell from '../../components/PageShell';
import TabMainHeader from '../../components/TabMainHeader';
import WechatShareReady from '../../components/WechatShareReady';
import RegionPicker from '../../components/RegionPicker';
import CategoryPicker, {
  EMPTY_CATEGORY,
  formatCategoryLabel,
  type CategorySelection,
  type StoreCategoryNode,
} from '../../components/CategoryPicker';
import {
  DEFAULT_REGION,
  formatRegionLabel,
  matchesRegionFilter,
  type RegionSelection,
} from '../../lib/region-data';
import UserTabBar, { shouldRenderPageTabBar, syncTabBarSelected } from '../../components/UserTabBar';
import {
  getCityCodeForCatalog,
  readCachedUserCoords,
  resolveUserCity,
  toCityWideRegion,
  type UserCoords,
} from '../../lib/user-location';
import { FALLBACK_CITY_CODE } from '../../lib/product-images';
import { formatDistanceMeters } from '../../lib/geo';
import { request, toast } from '../../lib/api';
import {
  getStoresListCache,
  isStoresSessionBootstrapped,
  markStoresSessionBootstrapped,
  patchStoresFilterCache,
  setStoresListCache,
} from '../../lib/stores-session';
import {
  DEFAULT_SHARE_DESC,
  DEFAULT_SHARE_TITLE,
  toWeappShareMessage,
} from '../../lib/wechat-share';

type Store = {
  id: string;
  name: string;
  address?: string;
  province?: string;
  cityName?: string;
  district?: string;
  coverUrl?: string | null;
  openTime?: string | null;
  closeTime?: string | null;
  openTime2?: string | null;
  closeTime2?: string | null;
  avgPrice?: number | null;
  status?: string;
  categoryId?: string | null;
  category?: { id?: string; name?: string; parentId?: string | null } | null;
  latitude?: number | string | null;
  longitude?: number | string | null;
  distanceMeters?: number | null;
};

function makeCityKey(region: Pick<RegionSelection, 'province' | 'city'>): string {
  return `${region.province}|${region.city}`;
}

/**
 * 定位城市若未开城，接口会 fallback 到郑州 cityCode；
 * 筛选器必须与真实拉取城市一致，否则列表被客户端滤空。
 */
function regionForCatalogFetch(resolved: {
  openCity: boolean;
  cityCode?: string;
  region: RegionSelection;
}): { cityCode: string; region: RegionSelection } {
  const cityCode = getCityCodeForCatalog(resolved);
  if (resolved.openCity && resolved.cityCode) {
    return { cityCode, region: toCityWideRegion(resolved.region) };
  }
  return { cityCode: FALLBACK_CITY_CODE, region: toCityWideRegion(DEFAULT_REGION) };
}

export default function StoresPage() {
  const cached = getStoresListCache();
  const [stores, setStores] = useState<Store[]>(() => (cached?.items as Store[] | undefined) ?? []);
  const [loading, setLoading] = useState(() => !cached && !isStoresSessionBootstrapped());
  const [keywordInput, setKeywordInput] = useState(() => cached?.keywordInput ?? '');
  const [keyword, setKeyword] = useState(() => cached?.keyword ?? '');
  const [region, setRegion] = useState<RegionSelection>(
    () => cached?.filterRegion ?? cached?.listRegion ?? DEFAULT_REGION,
  );
  const [regionOpen, setRegionOpen] = useState(false);
  const [category, setCategory] = useState<CategorySelection>(
    () => cached?.category ?? EMPTY_CATEGORY,
  );
  const [categoryOpen, setCategoryOpen] = useState(false);
  const [categoryTree, setCategoryTree] = useState<StoreCategoryNode[]>([]);
  const [locating, setLocating] = useState(false);
  const fetchCityKeyRef = useRef<string | null>(cached?.cityKey ?? null);
  const fetchSeqRef = useRef(0);
  const regionRef = useRef(region);
  regionRef.current = region;
  const regionLabel = formatRegionLabel(region);
  const categoryLabel = formatCategoryLabel(category);
  const showBootLoading = loading && stores.length === 0;

  const childIdsByParent = useMemo(() => {
    const map = new Map<string, string[]>();
    for (const root of categoryTree) {
      map.set(
        root.id,
        (root.children ?? []).map((c) => c.id),
      );
    }
    return map;
  }, [categoryTree]);

  async function fetchStores(
    nextCode: string,
    coords: UserCoords | null,
    cityKey: string,
    listRegion: RegionSelection,
    /** 写入会话的筛选器；默认保留用户当前选择 */
    filterRegion: RegionSelection = regionRef.current,
  ) {
    const seq = ++fetchSeqRef.current;
    const qs = new URLSearchParams();
    if (nextCode) qs.set('cityCode', nextCode);
    if (coords) {
      qs.set('lat', String(coords.latitude));
      qs.set('lng', String(coords.longitude));
    }
    const path = qs.toString() ? `/stores?${qs}` : '/stores';
    try {
      const list = await request<Store[]>(path);
      if (seq !== fetchSeqRef.current) return;
      const items = Array.isArray(list) ? list : [];
      setStores(items);
      fetchCityKeyRef.current = cityKey;
      const prev = getStoresListCache();
      setStoresListCache({
        cityKey,
        cityCode: nextCode,
        listRegion: toCityWideRegion(listRegion),
        items,
        filterRegion,
        keyword: prev?.keyword ?? keyword,
        keywordInput: prev?.keywordInput ?? keywordInput,
        category: prev?.category ?? category,
      });
    } catch (e) {
      if (seq !== fetchSeqRef.current) return;
      toast(e instanceof Error ? e.message : '加载失败');
    } finally {
      if (seq === fetchSeqRef.current) setLoading(false);
    }
  }

  /**
   * 首次进入：弹窗 + 定位 + 拉列表。
   * 同次再切回：只同步 tab 选中态，不改筛选、不拉接口、不 setState。
   */
  useDidShow(() => {
    syncTabBarSelected(1);

    if (isStoresSessionBootstrapped()) {
      return;
    }
    markStoresSessionBootstrapped();

    void (async () => {
      const { confirm } = await Taro.showModal({
        title: '获取当前位置',
        content: '是否允许获取当前位置来搜索附近门店？拒绝后将按默认城市展示，可下拉刷新重新定位。',
        confirmText: '允许',
        cancelText: '暂不',
      }).catch(() => ({ confirm: false, cancel: true }));

      if (confirm) {
        setLoading(true);
        const resolved = await resolveUserCity(true);
        const { cityCode, region: nextRegion } = regionForCatalogFetch(resolved);
        const nextCityKey = makeCityKey(nextRegion);
        setRegion(nextRegion);
        regionRef.current = nextRegion;
        await fetchStores(
          cityCode,
          readCachedUserCoords(),
          nextCityKey,
          nextRegion,
          nextRegion,
        );
        return;
      }

      const nextRegion = toCityWideRegion(DEFAULT_REGION);
      const nextCityKey = makeCityKey(nextRegion);
      setRegion(nextRegion);
      regionRef.current = nextRegion;
      setLoading(true);
      await fetchStores(FALLBACK_CITY_CODE, null, nextCityKey, nextRegion, nextRegion);
    })();
  });

  useEffect(() => {
    void request<StoreCategoryNode[]>('/store-categories')
      .then((tree) => setCategoryTree(Array.isArray(tree) ? tree : []))
      .catch(() => setCategoryTree([]));
  }, []);

  usePullDownRefresh(() => {
    void (async () => {
      try {
        const resolved = await resolveUserCity(true);
        const { cityCode, region: nextRegion } = regionForCatalogFetch(resolved);
        const nextCityKey = makeCityKey(nextRegion);
        setRegion(nextRegion);
        regionRef.current = nextRegion;
        if (fetchCityKeyRef.current !== nextCityKey) {
          setStores([]);
          setLoading(true);
        }
        await fetchStores(
          cityCode,
          readCachedUserCoords(),
          nextCityKey,
          nextRegion,
          nextRegion,
        );
      } catch (e) {
        toast(e instanceof Error ? e.message : '加载失败');
        setLoading(false);
      } finally {
        Taro.stopPullDownRefresh();
      }
    })();
  });

  function matchesCategory(store: Store): boolean {
    if (!category.parentId) return true;
    const storeCatId = String(store.categoryId || store.category?.id || '');
    const storeParentId = String(store.category?.parentId || '');
    if (category.childId) {
      return storeCatId === category.childId;
    }
    if (storeParentId && storeParentId === category.parentId) return true;
    const siblings = childIdsByParent.get(category.parentId) ?? [];
    return siblings.includes(storeCatId);
  }

  const filtered = stores.filter((s) => {
    if (!matchesRegionFilter(s, region)) return false;
    if (!matchesCategory(s)) return false;
    if (!keyword.trim()) return true;
    const q = keyword.trim();
    return s.name.includes(q) || (s.address ?? '').includes(q) || (s.district ?? '').includes(q);
  });

  function applySearch() {
    const next = keywordInput.trim();
    setKeyword(next);
    patchStoresFilterCache({ keyword: next, keywordInput });
  }

  function resetFilters() {
    setKeywordInput('');
    setKeyword('');
    setCategory(EMPTY_CATEGORY);
    setRegion(DEFAULT_REGION);
    regionRef.current = DEFAULT_REGION;
    patchStoresFilterCache({
      keyword: '',
      keywordInput: '',
      category: EMPTY_CATEGORY,
      filterRegion: DEFAULT_REGION,
    });
  }

  async function locateToUserRegion() {
    if (locating) return;
    const { confirm } = await Taro.showModal({
      title: '获取当前位置',
      content: '是否允许获取当前位置，并将筛选定位到您所在的城市与区县？',
      confirmText: '允许',
      cancelText: '暂不',
    }).catch(() => ({ confirm: false, cancel: true }));
    if (!confirm) return;

    setLocating(true);
    setLoading(true);
    try {
      const resolved = await resolveUserCity(true);
      // 筛选器用真实省市+区县；拉数仍按开城 cityCode（未开城则郑州）
      const filterRegion = resolved.region;
      const { cityCode, region: listRegion } = regionForCatalogFetch(resolved);
      const nextCityKey = makeCityKey(listRegion);
      setRegion(filterRegion);
      regionRef.current = filterRegion;
      await fetchStores(
        cityCode,
        readCachedUserCoords(),
        nextCityKey,
        listRegion,
        filterRegion,
      );
      toast(`已定位到${formatRegionLabel(filterRegion)}`, 'success');
    } catch (e) {
      toast(e instanceof Error ? e.message : '定位失败');
      setLoading(false);
    } finally {
      setLocating(false);
    }
  }

  function formatHours(store: Store) {
    const parts: string[] = [];
    if (store.openTime && store.closeTime) parts.push(`${store.openTime}-${store.closeTime}`);
    if (store.openTime2 && store.closeTime2) parts.push(`${store.openTime2}-${store.closeTime2}`);
    return parts.length ? `营业时间: ${parts.join('，')}` : '营业时间: 10:00-22:00';
  }

  const sharePayload = useMemo(
    () => ({
      title: '杜康好客门店',
      desc: DEFAULT_SHARE_DESC,
      path: '/pages/stores/index',
    }),
    [],
  );

  useShareAppMessage(() => toWeappShareMessage(sharePayload));
  useShareTimeline(() => ({
    title: sharePayload.title || DEFAULT_SHARE_TITLE,
    query: '',
  }));

  return (
    <PageShell variant="tab" className="store-page no-tab-header">
      <WechatShareReady payload={sharePayload} />
      <TabMainHeader title="门店" />

      <View className="store-filter">
        <View className="store-search-row">
          <Input
            className="store-search-input"
            placeholder="搜索门店名称/地址"
            value={keywordInput}
            confirmType="search"
            onInput={(e) => setKeywordInput(e.detail.value)}
            onConfirm={applySearch}
          />
          <View className="store-search-btn" onClick={applySearch} aria-label="搜索">
            <View className="store-search-icon" />
          </View>
        </View>

        <View className="store-filter-row">
          <View className="store-filter-chip" onClick={() => setRegionOpen(true)}>
            <Text className="store-filter-chip-text">{regionLabel}</Text>
            <Text className="store-filter-chip-arrow">▾</Text>
          </View>
          <View className="store-filter-chip" onClick={() => setCategoryOpen(true)}>
            <Text className="store-filter-chip-text">{categoryLabel}</Text>
            <Text className="store-filter-chip-arrow">▾</Text>
          </View>
          <View
            className="store-filter-icon-btn"
            onClick={resetFilters}
            aria-label="重置筛选"
          >
            {/* 小程序 View 伪元素不稳定，用 Text 保证真机可见 */}
            <Text className="store-filter-icon-glyph">↺</Text>
          </View>
          <View
            className={`store-filter-icon-btn${locating ? ' store-filter-icon-btn--busy' : ''}`}
            onClick={() => {
              void locateToUserRegion();
            }}
            aria-label="获取当前位置"
          >
            <Text className="store-filter-icon-glyph">⌖</Text>
          </View>
        </View>
      </View>

      <View className="store-list">
        {showBootLoading ? <View className="u-empty">加载中…</View> : null}
        {!showBootLoading && filtered.length === 0 ? (
          <View className="u-empty">暂无营业中门店</View>
        ) : null}
        {!showBootLoading &&
          filtered.map((s) => (
            <View
              key={s.id}
              className="store-card"
              onClick={() => Taro.navigateTo({ url: `/pages/store-detail/index?id=${s.id}` })}
            >
              {s.coverUrl ? (
                <Image className="store-card-cover" src={s.coverUrl} mode="aspectFill" />
              ) : (
                <View className="store-card-cover--empty" />
              )}
              <View className="store-card-body">
                <Text className="store-card-name">{s.name}</Text>
                <Text className="store-card-meta">
                  {s.district ? `${s.district} · ` : ''}
                  {s.address || '地址待完善'}
                </Text>
                <Text className="store-card-meta">{formatHours(s)}</Text>
                {s.avgPrice != null && Number(s.avgPrice) > 0 ? (
                  <Text className="store-card-meta">人均¥{Number(s.avgPrice).toFixed(0)}</Text>
                ) : null}
                <View className="store-card-footer">
                  <Text className="store-card-distance">
                    {formatDistanceMeters(s.distanceMeters)}
                  </Text>
                  <Text
                    className="store-card-cta"
                    onClick={(e) => {
                      e.stopPropagation();
                      Taro.navigateTo({ url: '/pages/redeem/index' });
                    }}
                  >
                    去核销
                  </Text>
                </View>
              </View>
            </View>
          ))}
      </View>

      {shouldRenderPageTabBar() ? <UserTabBar selected={1} /> : null}
      <RegionPicker
        open={regionOpen}
        value={region}
        levels={3}
        onClose={() => setRegionOpen(false)}
        onConfirm={(next) => {
          setRegion(next);
          regionRef.current = next;
          patchStoresFilterCache({ filterRegion: next });
        }}
      />
      <CategoryPicker
        open={categoryOpen}
        tree={categoryTree}
        value={category}
        onClose={() => setCategoryOpen(false)}
        onConfirm={(next) => {
          setCategory(next);
          patchStoresFilterCache({ category: next });
        }}
      />
    </PageShell>
  );
}
