<template>
  <view class="page">
    <NavBar title="设备绑定" :showBack="true" @back="goBack" />

    <!-- 补货员信息 -->
    <view class="header-card">
      <view class="hc-avatar">
        <text>{{ (replenisherName || '?')[0] }}</text>
      </view>
      <view class="hc-info">
        <text class="hc-name">{{ replenisherName }}</text>
        <text class="hc-hint">选择该补货员负责的设备</text>
      </view>
    </view>

    <!-- 绑定统计 -->
    <view class="bind-stats" v-if="!loading">
      <text>已选 <text class="bs-num">{{ selectedIds.length }}</text> 台设备</text>
    </view>

    <scroll-view class="page-scroll" scroll-y>
      <!-- 门店设备列表 -->
      <view class="shop-list" v-if="!loading">
        <view class="shop-group" v-for="shop in shopList" :key="shop.id">
          <view class="shop-header" @click="shop.expanded = !shop.expanded">
            <view class="sh-arrow" :class="{ expanded: shop.expanded }">
              <view class="arr-inner"></view>
            </view>
            <text class="sh-name">{{ shop.name }}</text>
            <text class="sh-count">{{ shop.devices.length }}台设备</text>
            <view class="sh-check" :class="{ partial: getShopState(shop) === 'partial', all: getShopState(shop) === 'all' }" @click.stop="toggleShopAll(shop)">
              <text v-if="getShopState(shop) === 'all'">✓</text>
              <text v-else-if="getShopState(shop) === 'partial'">-</text>
            </view>
          </view>
          <view class="shop-devices" v-if="shop.expanded">
            <view
              class="device-item"
              v-for="dev in shop.devices"
              :key="dev.deviceId"
              @click="toggleDevice(dev.deviceId)"
            >
              <view class="di-check" :class="{ on: selectedIds.includes(dev.deviceId) }">
                <text v-if="selectedIds.includes(dev.deviceId)">✓</text>
              </view>
              <text class="di-name">{{ dev.name || dev.deviceId }}</text>
              <text class="di-id">{{ dev.deviceId }}</text>
            </view>
            <view class="shop-empty" v-if="shop.devices.length === 0">
              <text>该门店暂无设备</text>
            </view>
          </view>
        </view>
      </view>

      <!-- 加载中 -->
      <view class="load-tip" v-if="loading">
        <view class="dot-row">
          <view class="pulse-dot"></view>
          <view class="pulse-dot"></view>
          <view class="pulse-dot"></view>
        </view>
      </view>

      <!-- 空状态 -->
      <view class="empty-state" v-if="!loading && shopList.length === 0">
        <text class="empty-text">暂无可用门店</text>
      </view>

      <view class="bottom-safe"></view>
    </scroll-view>

    <!-- 底部操作栏 -->
    <view class="bottom-bar" v-if="!loading">
      <view class="bb-info">
        <text>变更：绑定 {{ toBind.length }} 台，解绑 {{ toUnbind.length }} 台</text>
      </view>
      <view class="bb-btn" :class="{ disabled: toBind.length === 0 && toUnbind.length === 0 }" @click="handleSave">
        <text class="bb-btn-text">保存</text>
      </view>
    </view>
  </view>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import NavBar from '@/components/NavBar.vue';
import { getBoundDevices, bindDevices, unbindDevice } from '@/api/replenisher';
import { getEnabledShops, getShopDevices } from '@/api/shop';

const replenisherId = ref<string>('');
const replenisherName = ref('');
const loading = ref(true);
const saving = ref(false);
const selectedIds = ref<string[]>([]);
const origBoundIds = ref<string[]>([]);

interface ShopWithDevices {
  id: number;
  name: string;
  devices: { deviceId: string; name: string }[];
  expanded: boolean;
}

const shopList = ref<ShopWithDevices[]>([]);

const toBind = computed(() => selectedIds.value.filter(id => !origBoundIds.value.includes(id)));
const toUnbind = computed(() => origBoundIds.value.filter(id => !selectedIds.value.includes(id)));

const getShopState = (shop: ShopWithDevices): 'none' | 'partial' | 'all' => {
  if (shop.devices.length === 0) return 'none';
  const sel = shop.devices.filter(d => selectedIds.value.includes(d.deviceId)).length;
  if (sel === shop.devices.length) return 'all';
  if (sel > 0) return 'partial';
  return 'none';
};

const toggleDevice = (deviceId: string) => {
  const idx = selectedIds.value.indexOf(deviceId);
  if (idx >= 0) {
    selectedIds.value.splice(idx, 1);
  } else {
    selectedIds.value.push(deviceId);
  }
};

const toggleShopAll = (shop: ShopWithDevices) => {
  const allSelected = shop.devices.every(d => selectedIds.value.includes(d.deviceId));
  if (allSelected) {
    selectedIds.value = selectedIds.value.filter(id => !shop.devices.some(d => d.deviceId === id));
  } else {
    const toAdd = shop.devices.filter(d => !selectedIds.value.includes(d.deviceId)).map(d => d.deviceId);
    selectedIds.value = [...selectedIds.value, ...toAdd];
  }
};

const handleSave = async () => {
  if (saving.value) return;
  if (toBind.value.length === 0 && toUnbind.value.length === 0) {
    uni.showToast({ title: '未做任何变更', icon: 'none' });
    return;
  }
  saving.value = true;
  uni.showLoading({ title: '保存中...', mask: true });
  try {
    if (toBind.value.length > 0) {
      await bindDevices(replenisherId.value, toBind.value);
    }
    if (toUnbind.value.length > 0) {
      await Promise.all(toUnbind.value.map(deviceId => unbindDevice(replenisherId.value, deviceId)));
    }
    uni.hideLoading();
    uni.showToast({ title: '保存成功', icon: 'success' });
    setTimeout(() => {
      uni.navigateBack();
    }, 1200);
  } catch (e) {
    uni.hideLoading();
    uni.showToast({ title: '保存失败', icon: 'none' });
  } finally {
    saving.value = false;
  }
};

const goBack = () => {
  uni.navigateBack();
};

onMounted(async () => {
  const pages = getCurrentPages();
  const page = pages[pages.length - 1];
  const options = (page as any).options || {};
  replenisherId.value = options.id || '';
  replenisherName.value = decodeURIComponent(options.name || '');

  if (!replenisherId.value) {
    uni.showToast({ title: '参数错误', icon: 'none' });
    return;
  }

  try {
    const [shops, boundDevices] = await Promise.all([
      getEnabledShops(),
      getBoundDevices(replenisherId.value)
    ]);
    origBoundIds.value = boundDevices || [];
    selectedIds.value = [...origBoundIds.value];

    // 并行获取每个门店的设备
    const shopPromises = (shops || []).map(async (shop: any) => {
      try {
        const devices = await getShopDevices(shop.id);
        return {
          id: shop.id,
          name: shop.name,
          devices: (devices || []).map((d: any) => ({
            deviceId: d.deviceId,
            name: d.name || d.deviceId
          })),
          expanded: false
        };
      } catch {
        return { id: shop.id, name: shop.name, devices: [], expanded: false };
      }
    });
    shopList.value = await Promise.all(shopPromises);
  } catch (e) {
    uni.showToast({ title: '加载失败', icon: 'none' });
  } finally {
    loading.value = false;
  }
});
</script>

<style lang="scss" scoped>
$font-stack: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', system-ui, sans-serif;

.page {
  height: 100vh;
  width: 100vw;
  overflow-x: hidden;
  background: $bg-color-page;
  display: flex;
  flex-direction: column;
  font-family: $font-stack;
}

// ====== Header ======
.header-card {
  display: flex;
  align-items: center;
  background: $bg-color-card;
  padding: 24rpx 32rpx;
  gap: 20rpx;
  flex-shrink: 0;
}

.hc-avatar {
  width: 72rpx;
  height: 72rpx;
  border-radius: 50%;
  background: $primary-color-bg;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;

  text {
    font-size: 32rpx;
    font-weight: 700;
    color: $primary-color-dark;
  }
}

.hc-info {
  flex: 1;
  min-width: 0;
}

.hc-name {
  font-size: 30rpx;
  font-weight: 600;
  color: $text-color-primary;
  display: block;
}

.hc-hint {
  font-size: 24rpx;
  color: $text-color-muted;
  margin-top: 4rpx;
  display: block;
}

// ====== Stats ======
.bind-stats {
  padding: 16rpx 32rpx;
  font-size: 24rpx;
  color: $text-color-muted;
  flex-shrink: 0;

  .bs-num {
    font-weight: 600;
    color: $primary-color-dark;
  }
}

// ====== Scroll ======
.page-scroll {
  flex: 1;
  height: 0;
  padding: 0 24rpx;
}

// ====== Shop list ======
.shop-group {
  background: $bg-color-card;
  border-radius: 16rpx;
  margin-bottom: 16rpx;
  overflow: hidden;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
}

.shop-header {
  display: flex;
  align-items: center;
  padding: 20rpx 20rpx 20rpx 16rpx;
  gap: 12rpx;
  &:active { background: $bg-color-page; }
}

.sh-arrow {
  width: 32rpx;
  height: 32rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: transform 0.2s ease;

  .arr-inner {
    width: 12rpx; height: 12rpx;
    border-top: 2rpx solid $text-color-placeholder;
    border-right: 2rpx solid $text-color-placeholder;
    transform: rotate(45deg);
  }

  &.expanded {
    transform: rotate(90deg);
  }
}

.sh-name {
  flex: 1;
  font-size: 28rpx;
  font-weight: 600;
  color: $text-color-primary;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sh-count {
  font-size: 22rpx;
  color: $text-color-muted;
  flex-shrink: 0;
}

.sh-check {
  width: 36rpx;
  height: 36rpx;
  border-radius: 8rpx;
  border: 2rpx solid $border-color;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 24rpx;
  color: transparent;
  transition: all 0.15s ease;

  &.partial {
    background: $primary-color-bg;
    border-color: $primary-color;
    color: $primary-color-dark;
  }

  &.all {
    background: $primary-color;
    border-color: $primary-color;
    color: $text-color-primary;
  }
}

// ====== Device items ======
.shop-devices {
  border-top: 1rpx solid $border-color-light;
}

.device-item {
  display: flex;
  align-items: center;
  padding: 18rpx 20rpx 18rpx 48rpx;
  gap: 14rpx;
  &:active { background: $bg-color-page; }

  &:not(:last-child) {
    border-bottom: 1rpx solid $border-color-light;
  }
}

.di-check {
  width: 32rpx;
  height: 32rpx;
  border-radius: 8rpx;
  border: 2rpx solid $border-color;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 20rpx;
  color: transparent;
  transition: all 0.15s ease;

  &.on {
    background: $primary-color;
    border-color: $primary-color;
    color: $text-color-primary;
  }
}

.di-name {
  flex: 1;
  font-size: 26rpx;
  color: $text-color-primary;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.di-id {
  font-size: 22rpx;
  color: $text-color-muted;
  flex-shrink: 0;
}

.shop-empty {
  padding: 32rpx 0;
  text-align: center;
  font-size: 24rpx;
  color: $text-color-placeholder;
}

// ====== Bottom bar ======
.bottom-bar {
  display: flex;
  align-items: center;
  padding: 20rpx 24rpx;
  padding-bottom: calc(20rpx + constant(safe-area-inset-bottom));
  padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
  background: $bg-color-card;
  border-top: 1rpx solid $border-color-light;
  gap: 20rpx;
  flex-shrink: 0;
}

.bb-info {
  flex: 1;
  font-size: 22rpx;
  color: $text-color-muted;
}

.bb-btn {
  background: $primary-color;
  border-radius: 40rpx;
  padding: 18rpx 48rpx;
  transition: opacity 0.15s ease;

  &:active { opacity: 0.8; }

  &.disabled {
    opacity: 0.4;
    pointer-events: none;
  }
}

.bb-btn-text {
  font-size: 28rpx;
  font-weight: 600;
  color: $text-color-primary;
}

// ====== Load / Empty ======
.load-tip {
  display: flex;
  justify-content: center;
  padding: 60rpx 0;
}

.dot-row {
  display: flex;
  gap: 8rpx;
}

.pulse-dot {
  width: 9rpx; height: 9rpx;
  background: $text-color-placeholder;
  border-radius: 50%;
  animation: pulse 1.2s ease-in-out infinite;
  &:nth-child(2) { animation-delay: 0.2s; }
  &:nth-child(3) { animation-delay: 0.4s; }
}

@keyframes pulse {
  0%, 80%, 100% { transform: scale(0.5); opacity: 0.4; }
  40% { transform: scale(1); opacity: 1; }
}

.empty-state {
  display: flex;
  justify-content: center;
  padding: 80rpx 0;
}

.empty-text {
  font-size: 28rpx;
  color: $text-color-muted;
}

.bottom-safe {
  height: 40rpx;
}
</style>
