import { useEffect, useRef, useState } from 'react'
import Taro from '@tarojs/taro'
import { Input, View } from '@tarojs/components'
import CustomNavBar from '@/components/layout/CustomNavBar'
import Icon from '@/components/ui/Icon'
import ToastOverlay from '@/components/feedback/ToastOverlay'
import NearbyMap, { NEARBY_MAP_ID } from '@/features/nearby/components/NearbyMap'
import MapControls from '@/features/nearby/components/MapControls'
import NearbySheet from '@/features/nearby/components/NearbySheet'
import { useSystemLayout } from '@/hooks/useSystemLayout'
import { getNearbyPets, likeNearbyPet, updateLocation } from '@/services/nearby.service'
import { getProfile } from '@/services/profile.service'
import { toggleFollow } from '@/services/social.service'
import { useToast } from '@/hooks/useToast'
import { ensureProfileReady } from '@/store/session.store'
import type { GeoPoint, NearbyPet } from '@/types/domain'
import type { TabViewProps } from '@/components/navigation/BottomTabBar/tabConfig'
import './index.scss'

// Fallback centre (Shanghai) when the user denies or has no location.
const DEFAULT_CENTER: GeoPoint = { latitude: 31.2304, longitude: 121.4737 }
const MIN_SCALE = 4
const MAX_SCALE = 20

// Nearby doesn't refresh on tab return (matches its original behaviour), so the
// host's active/showTick props are accepted only for a uniform tab-view type.
export default function NearbyPage(_props: TabViewProps) {
  const { navHeight } = useSystemLayout()
  const [pets, setPets] = useState<NearbyPet[]>([])
  const [activeId, setActiveId] = useState<string | undefined>()
  const [filter, setFilter] = useState('all')
  const [center, setCenter] = useState<GeoPoint | null>(null)
  const [scale, setScale] = useState(15)
  const [query, setQuery] = useState('')
  const [nearbyVisible, setNearbyVisible] = useState<boolean | null>(null)
  const pendingLikeIds = useRef<Set<string>>(new Set())
  const toast = useToast(480)

  const applyPets = (result: NearbyPet[]) => {
    setPets(result)
    setActiveId(current => (current && result.some(pet => pet._id === current) ? current : result[0]?._id))
  }

  // Load the user's preference before requesting location or nearby data.
  useEffect(() => {
    let ignored = false
    getProfile()
      .then(({ user }) => {
        if (!ignored) setNearbyVisible(user.preferences.nearbyVisible)
      })
      .catch(() => {
        if (!ignored) setNearbyVisible(true)
      })
    return () => {
      ignored = true
    }
  }, [])

  // Resolve and upload the user's location only when nearby discovery is enabled.
  useEffect(() => {
    if (nearbyVisible === null) return

    let ignored = false
    if (!nearbyVisible) {
      setPets([])
      setActiveId(undefined)
      setCenter(DEFAULT_CENTER)
      updateLocation(null, false).catch(() => undefined)
      return
    }

    Taro.getLocation({ type: 'gcj02' })
      .then(res => {
        if (ignored) return
        const loc = { latitude: res.latitude, longitude: res.longitude }
        setCenter(loc)
        updateLocation(loc, true).catch(() => undefined)
      })
      .catch(() => {
        if (!ignored) setCenter(DEFAULT_CENTER)
      })

    return () => {
      ignored = true
    }
  }, [nearbyVisible])

  const loadPets = (loc: GeoPoint, currentFilter = filter) => {
    getNearbyPets(loc, currentFilter).then(applyPets)
  }

  // Load nearby pets relative to the resolved centre, re-loading on filter change.
  useEffect(() => {
    if (!center || nearbyVisible !== true) return
    let ignored = false
    getNearbyPets(center, filter).then(result => {
      if (!ignored) applyPets(result)
    })
    return () => {
      ignored = true
    }
  }, [center, filter, nearbyVisible])

  const relocate = () => {
    if (nearbyVisible === null) {
      Taro.showToast({ title: '正在读取设置', icon: 'none' })
      return
    }

    if (nearbyVisible === false) {
      Taro.showToast({ title: '附近可见已关闭', icon: 'none' })
      return
    }

    Taro.getLocation({ type: 'gcj02' })
      .then(res => {
        const loc = { latitude: res.latitude, longitude: res.longitude }
        setCenter(loc)
        updateLocation(loc, true).catch(() => undefined)
      })
      .catch(() => {
        Taro.showModal({
          title: '需要位置权限',
          content: '请在右上角「···」→ 设置中允许获取位置后重试',
          showCancel: false
        })
      })
  }

  // Sync our scale only after a user pinch-zoom (causedBy 'scale'), so the
  // programmatic +/- buttons aren't reverted by a read-back race.
  const onRegionChange = (causedBy: string) => {
    if (causedBy !== 'scale') return
    try {
      Taro.createMapContext(NEARBY_MAP_ID).getScale({
        success: (r: any) => {
          if (r?.scale) setScale(Math.round(r.scale))
        }
      })
    } catch {
      /* map context not ready */
    }
  }

  const zoomIn = () => setScale(s => Math.min(MAX_SCALE, s + 1))
  const zoomOut = () => setScale(s => Math.max(MIN_SCALE, s - 1))
  const refresh = () => {
    if (nearbyVisible === null) {
      Taro.showToast({ title: '正在读取设置', icon: 'none' })
      return
    }

    if (nearbyVisible === false) {
      Taro.showToast({ title: '附近可见已关闭', icon: 'none' })
      return
    }
    if (center) loadPets(center)
    Taro.showToast({ title: '已刷新附近', icon: 'none' })
  }

  const likePet = async (id: string) => {
    if (!(await ensureProfileReady())) return
    const target = pets.find(pet => pet._id === id)
    if (target?.likedByMe) {
      Taro.showToast({ title: '已经喜欢过啦', icon: 'none' })
      return
    }
    if (pendingLikeIds.current.has(id)) return

    pendingLikeIds.current.add(id)
    const previousLiked = Boolean(target?.likedByMe)
    setPets(current =>
      current.map(pet => (pet._id === id ? { ...pet, likedByMe: true } : pet))
    )
    toast.show()
    try {
      const result = await likeNearbyPet(id)
      if (result.matched) Taro.showToast({ title: '互相喜欢啦', icon: 'none' })
    } catch {
      setPets(current =>
        current.map(pet => (pet._id === id ? { ...pet, likedByMe: previousLiked } : pet))
      )
      Taro.showToast({ title: '喜欢失败，请稍后再试', icon: 'none' })
    } finally {
      pendingLikeIds.current.delete(id)
    }
  }

  const updateOwnerRelation = (
    ownerId: string,
    patch: Pick<NearbyPet, 'isFollowing' | 'isFriend'>
  ) => {
    setPets(current => current.map(pet => (pet.ownerId === ownerId ? { ...pet, ...patch } : pet)))
  }

  const openChatWithPet = (pet: NearbyPet) => {
    if (!pet.ownerId) return
    ensureProfileReady().then(ready => {
      if (!ready) return
      const title = pet.ownerName || pet.name
      Taro.navigateTo({
        url: `/pages/chat/index?targetUserId=${pet.ownerId}&title=${encodeURIComponent(title)}`
      })
    })
  }

  const handleFriendAction = async (pet: NearbyPet) => {
    if (!(await ensureProfileReady())) return
    if (pet.isMine) {
      Taro.showToast({ title: '这是你自己的毛孩子', icon: 'none' })
      return
    }

    if (pet.isFriend) {
      openChatWithPet(pet)
      return
    }

    if (pet.isFollowing) {
      Taro.showToast({ title: '已关注，等对方回关', icon: 'none' })
      return
    }

    updateOwnerRelation(pet.ownerId, { isFollowing: true, isFriend: false })
    try {
      const result = await toggleFollow(pet.ownerId, true)
      updateOwnerRelation(pet.ownerId, { isFollowing: true, isFriend: result.mutual })
      Taro.showToast({
        title: result.mutual ? '已成为汪友' : '已关注，等对方回关',
        icon: 'none'
      })
    } catch {
      updateOwnerRelation(pet.ownerId, { isFollowing: false, isFriend: false })
      Taro.showToast({ title: '添加失败，请稍后再试', icon: 'none' })
    }
  }

  const q = query.trim().toLowerCase()
  const visiblePets = q
    ? pets.filter(p => p.name.toLowerCase().includes(q) || (p.breed || '').toLowerCase().includes(q))
    : pets

  return (
    <View className='nearby-page'>
      <NearbyMap
        pets={visiblePets}
        center={center || DEFAULT_CENTER}
        scale={scale}
        activeId={activeId}
        onSelect={setActiveId}
        onRegionChange={onRegionChange}
      />
      <CustomNavBar />
      <View className='nearby-page__search' style={{ top: `${navHeight + 6}px` }}>
        <Icon name='search' size={14} />
        <Input
          className='nearby-page__search-input'
          value={query}
          placeholder='搜索名字 / 品种'
          placeholderClass='nearby-page__search-ph'
          confirmType='search'
          onInput={e => setQuery(e.detail.value)}
        />
        {query ? (
          <View className='nearby-page__search-clear' onClick={() => setQuery('')}>
            <Icon name='close' size={14} />
          </View>
        ) : null}
      </View>
      <MapControls onRefresh={refresh} onZoomIn={zoomIn} onZoomOut={zoomOut} onLocate={relocate} />
      <NearbySheet
        pets={visiblePets}
        activeId={activeId}
        filter={filter}
        state={nearbyVisible === null ? 'loading' : nearbyVisible === false ? 'disabled' : 'ready'}
        onFilterChange={setFilter}
        onSelect={setActiveId}
        onFriendAction={handleFriendAction}
        onLike={likePet}
      />
      <ToastOverlay visible={toast.visible} />
    </View>
  )
}
