<template>
  <div class="dispatch-container">
    <!-- Top Filter Bar -->
    <div class="top-filter-bar glass-panel-sm">
      <div class="filter-left">
        <el-radio-group v-model="filters.orderType" size="default" fill="#2d8cf0">
          <el-radio-button label="all">全部</el-radio-button>
          <el-radio-button v-for="item in serviceOnOrderList" :key="item.id" :label="item.id">{{ item.name
          }}</el-radio-button>
        </el-radio-group>
      </div>
        <el-cascader
          v-model="regionValue"
          :options="areaOptions"
          placeholder="所属站点"
          clearable
          style="width: 240px"
          @change="handleAreaChange"
        />
    </div>

    <div class="main-content">
      <!-- Left: Real Gaode Map Area -->
      <div class="map-wrapper">
        <template v-if="checkPermi(['order:dispatch:map'])">
          <div v-if="!mapLoadError" id="amap-container" class="map-view"></div>
          
          <!-- 地图加载失败提示 -->
          <div v-else class="map-error-state">
            <div class="error-content">
              <el-icon class="error-icon"><CircleCloseFilled /></el-icon>
              <h3 class="error-title">地图加载失败</h3>
              <p class="error-desc">请检查系统设置中的高德地图配置或联系管理员处理</p>
              <el-button type="primary" plain size="small" @click="retryLoadMap">重试加载</el-button>
            </div>
          </div>

          <!-- Bottom Left: Map Controls & Stats -->
          <div v-if="!mapLoadError" class="map-controls-panel">
            <div class="control-group">
              <div class="c-btn" :class="{ active: activeMapFilter === 'all' }" @click="setMapFilter('all')">全部</div>
              <div class="c-btn red" :class="{ active: activeMapFilter === 'merchants' }"
                @click="setMapFilter('merchants')">商家({{ merchantList.length }})</div>
              <div class="c-btn green" :class="{ active: activeMapFilter === 'fulfillers' }"
                @click="setMapFilter('fulfillers')">履约者({{ ridersList.length }})</div>
              <div class="c-btn blue" :class="{ active: activeMapFilter === 'orders' }" @click="setMapFilter('orders')">
                订单({{ ordersList.length }})</div>
              <div class="c-btn gray">灰色表示离线</div>
            </div>
          </div>
        </template>
        <div v-else class="no-auth-map">
          <div class="no-auth-content">
            <div class="lock-icon">
              <!-- Inline SVG for Lock Icon -->
              <svg viewBox="0 0 1024 1024" width="64" height="64">
                <path d="M512 64a256 256 0 0 0-256 256v128h-64a64 64 0 0 0-64 64v384a64 64 0 0 0 64 64h640a64 64 0 0 0 64-64V512a64 64 0 0 0-64-64h-64V320a256 256 0 0 0-256-256z m160 384H352V320a160 160 0 1 1 320 0v128z" fill="#E4E7ED"/>
              </svg>
            </div>
            <h3 class="no-auth-title">暂无地图权限</h3>
            <p class="no-auth-desc">当前角色尚未分配地图查看权限，无法展示实时调度数据</p>
          </div>
        </div>
      </div>

      <!-- Right: Dispatch Control Panel -->
      <div class="right-panel">
        <OrderListPanel v-model="currentOrderTab" :orders="filteredOrders" :stats="orderStats" @focus="focusMapPoint"
          @dispatch="openDispatchDialog" />

        <RiderListPanel v-model="currentRiderTab" :riders="filteredRiders" :stats="riderStats" @focus="focusMapPoint"
          @view-orders="handleViewRiderOrders" />
      </div>
    </div>

    <RiderOrdersDialog v-model="riderOrdersVisible" :riderInfo="currentRiderInfo" :orders="currentRiderOrders" />

    <DispatchDialog v-model:visible="dispatchDialogVisible" :order="currentDispatchOrder"
      @success="getOrdersList" />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, reactive, onMounted, onUnmounted, watch, getCurrentInstance, ComponentInternalInstance } from 'vue';
import { checkPermi } from "@/utils/permission";
import { ElMessage } from 'element-plus';
import { listAllService } from '@/api/service/list/index'
import { listAreaStation } from '@/api/system/areaStation'
import { getMapSetting } from '@/api/system/mapSetting';
import { CircleCloseFilled } from '@element-plus/icons-vue';
import { listStoreOnDispatch } from '@/api/system/store/index'
import { listSubOrderOnDispatch } from '@/api/order/subOrder/index';
import { listFulfillerOnDispatch } from '@/api/fulfiller/pool/index'
import { getFulfillerGps } from '@/api/fulfiller/fulfiller/index'

import OrderListPanel from './components/OrderListPanel.vue';
import RiderListPanel from './components/RiderListPanel.vue';
import RiderOrdersDialog from './components/RiderOrdersDialog.vue';
import DispatchDialog from '@/components/DispatchDialog/index.vue';
import { useIntervalRefresh } from '@/hooks/useIntervalRefresh';

// Mock Data
import dispatchMockData from '@/mock/dispatch.json';
import riderOrdersMockData from '@/mock/RiderOrdersDialog.json';

const { proxy } = getCurrentInstance() as ComponentInternalInstance;

// --- Data & State ---
const filters = reactive({
  orderType: 'all',
  station: undefined
});

const currentOrderTab = ref('PendingDispatch');
const currentRiderTab = ref('All');
const activeMapFilter = ref('all');

const ordersList = ref([]);
const ridersList = ref([]);
const merchantList = ref([]);
const orderStats = computed(() => ({
  pendingDispatch: ordersList.value.filter(o => o.status === 0).length,
  pendingAccept: ordersList.value.filter(o => o.status === 1).length,
  processing: ordersList.value.filter(o => [2, 3].includes(o.status)).length
}));

const riderStats = computed(() => ({
  all: ridersList.value.length,
  working: ridersList.value.filter(r => r.uiStatus === 'busy').length,
  resting: ridersList.value.filter(r => r.uiStatus === 'offline').length,
  disabled: ridersList.value.filter(r => r.uiStatus === 'disabled').length
}));

const serviceOnOrderList = ref([])

const getServiceList = () => {
  listAllService().then(res => {
    serviceOnOrderList.value = res?.data || []
  }).catch(() => {
    serviceOnOrderList.value = []
  })
}

const getOrdersList = () => {
  if (!filters.station) return;
  listSubOrderOnDispatch({
    service: filters.orderType !== 'all' ? filters.orderType : undefined,
    site: filters.station
  }).then(res => {
    const list = (res?.data || []).map(item => {
      const typeName = getServiceName(item.service);
      const isTransport = item.mode === 1 || item.mode === '1';
      const typeCode = isTransport ? 'transport' : typeName?.includes('喂') || typeName?.includes('遛') ? 'feeding' : 'washing';

      // 模拟经纬度
      return {
        ...item,
        typeCode,
        lng: item.lng || (116.4 + Math.random() * 0.1),
        lat: item.lat || (39.9 + Math.random() * 0.05)
      };
    });
    ordersList.value = list;
  })
}

// 统一数据轮询 @Author: Antigravity
useIntervalRefresh(getOrdersList, 5000);

const getServiceName = (serviceId) => {
  const item = serviceOnOrderList.value.find((i) => i.id === serviceId);
  return item ? item.name : '未知服务';
};

const getRidersList = async () => {
  if (!filters.station) return;
  try {
    const res = await listFulfillerOnDispatch({
      service: filters.orderType !== 'all' ? filters.orderType : undefined,
      site: filters.station
    });
    const baseList = (res.data || []).map(r => ({
      ...r,
      uiStatus: r.status === 'busy' ? 'busy' : r.status === 'resting' ? 'offline' : 'disabled',
      maskPhone: r.phone ? r.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : '',
      categories: (r.serviceTypes || '').split(',').map(id => {
        const s = serviceOnOrderList.value.find(item => String(item.id) === String(id));
        return s ? s.name.substring(0, 2) : '服务';
      }),
      nextOrderTime: r.nextOrderTime || '14:30',
      // GPS 坐标初始为 null，等待并发请求后覆盖
      lng: null,
      lat: null
    }));

    // 并发请求所有骑手的实时 GPS 坐标
    const gpsResults = await Promise.allSettled(
      baseList.map(r => getFulfillerGps(r.id))
    );

    ridersList.value = baseList.map((r, idx) => {
      const result = gpsResults[idx];
      // 只有当 data 不为空且含有经纬度数据时才赋値
      if (result.status === 'fulfilled' && result.value?.data) {
        const gps = result.value.data;
        if (gps.longitude && gps.latitude) {
          return { ...r, lng: gps.longitude, lat: gps.latitude };
        }
      }
      return r; // 无数据保持 lng/lat 为 null，不在地图上显示
    });

    refreshMarkers();
  } catch {
    ridersList.value = [];
    refreshMarkers();
  }
}

const getMerchantList = () => {
  if (!filters.station) {
    merchantList.value = [];
    refreshMarkers();
    return;
  }
  listStoreOnDispatch({ site: filters.station }).then(res => {
    // 保留全量门店数据（用于统计数字），有坐标的赋 lng/lat，无坐标则不在地图打点
    merchantList.value = (res?.data || []).map(item => ({
      ...item,
      lng: item.longitude || null,
      lat: item.latitude || null
    }));
    refreshMarkers();
  }).catch(() => {
    merchantList.value = [];
    refreshMarkers();
  });
}

watch([() => filters.orderType, () => filters.station], () => {
  if (!filters.station) {
    ordersList.value = [];
    ridersList.value = [];
    merchantList.value = [];
    refreshMarkers();
    return;
  }
  getOrdersList();
  getRidersList();
  getMerchantList();
});

const areaStationList = ref([])
const areaOptions = ref([])
const regionValue = ref([])

const buildTree = (data, parentId) => {
  return (data || [])
    .filter(item => String(item.parentId) === String(parentId))
    .map(item => {
      const children = buildTree(data, item.id);
      const node: any = {
        value: item.id,
        label: item.name,
        // 如果不是站点且没有下级了，则不可选（防止误选区域叶子点）
        disabled: Number(item.type) !== 2 && (!children || children.length === 0)
      };
      if (children && children.length > 0) {
        node.children = children;
      }
      return node;
    })
}

const handleAreaChange = (value) => {
  if (value && value.length > 0) {
    filters.station = value[value.length - 1];
  } else {
    filters.station = undefined;
  }
}

const getAreaStationList = async () => {
  try {
    const res = await listAreaStation()
    const data = res?.data || res
    areaStationList.value = Array.isArray(data) ? data : []
    areaOptions.value = buildTree(areaStationList.value, 0)

    // 默认选中第一个站点（如果存在）
    const allStations = areaStationList.value.filter(item => Number(item.type) === 2)
    if (allStations.length > 0) {
      const randomStation = allStations[Math.floor(Math.random() * allStations.length)]
      const path = []
      let currentId = randomStation.id
      while (currentId && String(currentId) !== '0') {
        path.unshift(currentId)
        const node = areaStationList.value.find(item => String(item.id) === String(currentId))
        if (node) {
          currentId = node.parentId
        } else {
          break
        }
      }
      regionValue.value = path
      filters.station = randomStation.id
    }
  } catch (error) {
    console.error('getAreaStationList error:', error);
    areaStationList.value = []
    areaOptions.value = []
  }
}

// Rider Orders State
const riderOrdersVisible = ref(false);
const currentRiderInfo = ref(null);
const currentRiderOrders = ref([]);

const handleViewRiderOrders = (rider) => {
  currentRiderInfo.value = {
    name: rider.name,
    maskPhone: rider.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2'),
    station: rider.station + ' - 东城片区',
    workType: '全职专送',
    categories: ['宠物接送', '上门喂遛', '洗护套餐']
  };
  currentRiderOrders.value = riderOrdersMockData.orders;
  riderOrdersVisible.value = true;
};

// --- Map Logic ---
let map = null;
const mapLoadError = ref(false);

/** 动态加载高德地图脚本 */
const loadAMapScript = async (): Promise<any> => {
  try {
    const res = await getMapSetting(1);
    if (res.code !== 200) throw new Error(res.msg);
    const { apiKey, apiSecret } = res.data;

    if (!apiKey) {
      throw new Error('No Map Key Configured');
    }

    // 设置安全密钥
    (window as any)._AMapSecurityConfig = {
      securityJsCode: apiSecret,
    };

    return new Promise((resolve, reject) => {
      if ((window as any).AMap) {
        resolve((window as any).AMap);
        return;
      }
      const script = document.createElement('script');
      script.src = `https://webapi.amap.com/maps?v=2.0&key=${apiKey}`;
      script.onload = () => resolve((window as any).AMap);
      script.onerror = () => reject(new Error('Script Load Error'));
      document.head.appendChild(script);
    });
  } catch (error) {
    console.error('Map config fetch error:', error);
    return Promise.reject(error);
  }
};

const initMap = async () => {
  try {
    mapLoadError.value = false;
    await loadAMapScript();
    
    const AMap = (window as any).AMap;
    if (!AMap) throw new Error('AMap Init Fail');

    map = new AMap.Map('amap-container', {
      zoom: 14,
      center: [116.4551, 39.9255], // Chaoyang center
      mapStyle: 'amap://styles/normal'
    });

    refreshMarkers();
  } catch (err) {
    console.error('initMap failed', err);
    mapLoadError.value = true;
  }
};

/** 重试加载地图 */
const retryLoadMap = () => {
  initMap();
};

const refreshMarkers = () => {
  if (!map) return;
  map.clearMap(); // 清除所有标记

  const filter = activeMapFilter.value;

  // 1. Merchants (商家) - 仅对有经纬度的门店打点
  if (filter === 'all' || filter === 'merchants') {
    merchantList.value.filter(m => m.lng && m.lat).forEach((m) => {
      const iconImg = m.icon || 'https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png';

      const content = `
            <div style="position:relative; width: 220px; filter: drop-shadow(0 4px 10px rgba(0,0,0,0.2));">
                <div style="background:#fff; border-radius:8px; padding: 12px; display: flex; align-items: center; gap: 10px; position: relative;">
                    <!-- Icon Ring -->
                    <div style="width: 48px; height: 48px; border-radius: 50%; border: 4px solid #F56C6C; padding: 2px; flex-shrink: 0; box-sizing: border-box; display: flex; align-items: center; justify-content: center;">
                         <img src="${iconImg}" style="width: 100%; height: 100%; border-radius: 50%; object-fit: cover;">
                    </div>

                    <!-- Info -->
                    <div style="flex: 1; overflow: hidden;">
                        <div style="font-weight: bold; font-size: 14px; color: #333; margin-bottom: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${m.name}</div>
                        <div style="font-size: 12px; color: #666;">今日 <span style="color: #F56C6C; font-weight: bold; font-size: 14px;">0</span> 单</div>
                    </div>
                </div>
                <!-- Triangle -->
                <div style="width: 0; height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 10px solid #fff; margin: 0 auto; margin-top: -1px;"></div>
            </div>
            `;

      const marker = new AMap.Marker({
        position: [m.lng, m.lat],
        content: content,
        offset: new AMap.Pixel(-110, -85)
      });
      map.add(marker);
    });
  }

  // 2. Fulfiller (履约者) - 仅对有真实 GPS 坐标的骑手打点
  if (filter === 'all' || filter === 'fulfillers') {
    ridersList.value.filter(r => r.lng && r.lat).forEach((r) => {
      const borderColor = r.uiStatus === 'busy' ? '#67C23A' : r.uiStatus === 'offline' ? '#909399' : '#F56C6C';
      const avatar = r.avatar || 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png';

      const content = `
            <div style="position:relative; width: 200px; filter: drop-shadow(0 4px 10px rgba(0,0,0,0.2));">
                <div style="background:#fff; border-radius:8px; padding: 10px; display: flex; align-items: center; gap: 10px; position: relative;">
                    <!-- Avatar Ring -->
                    <div style="width: 44px; height: 44px; border-radius: 50%; border: 3px solid ${borderColor}; padding: 1px; flex-shrink: 0; box-sizing: border-box;">
                        <img src="${avatar}" style="width: 100%; height: 100%; border-radius: 50%; object-fit: cover;">
                    </div>

                    <!-- Info -->
                    <div style="flex: 1; overflow: hidden;">
                        <div style="font-weight: bold; font-size: 13px; color: #333; margin-bottom: 2px;">[履约者]${r.name}</div>
                        <div style="font-size: 12px; color: #999;">${r.maskPhone}</div>
                    </div>
                </div>
                 <!-- Triangle -->
                <div style="width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 8px solid #fff; margin: 0 auto; margin-top: -1px;"></div>
            </div>
            `;

      const marker = new AMap.Marker({
        position: [r.lng, r.lat],
        content: content,
        offset: new AMap.Pixel(-100, -75)
      });
      map.add(marker);
    });
  }

  // 3. Orders (订单)
  if (filter === 'all' || filter === 'orders') {
    filteredOrders.value.forEach((o) => {
      // 默认点标记 + 文本标注
      const labelContent = `<div style="border:1px solid #409EFF;background:#fff;color:#409EFF;padding:2px 6px;border-radius:4px;font-size:12px;">${getServiceName(o.service)}</div>`;

      const marker = new AMap.Marker({
        position: [o.lng, o.lat],
        label: {
          content: labelContent,
          direction: 'top',
          offset: new AMap.Pixel(0, -5)
        }
      });
      map.add(marker);
    });
  }
};

const setMapFilter = (val) => {
  activeMapFilter.value = val;
};

const focusMapPoint = (lng, lat) => {
  if (!map) return;
  map.setCenter([lng, lat]);
  map.setZoom(16);
};

watch(activeMapFilter, () => {
  refreshMarkers();
});

watch([currentOrderTab, currentRiderTab], () => {
  refreshMarkers();
});

onMounted(async () => {
  getServiceList()
  await getAreaStationList()
  if (checkPermi(['order:dispatch:map'])) {
    initMap();
  }
});

// Dispatch Dialog State
const dispatchDialogVisible = ref(false);
const currentDispatchOrder = ref(null);
const currentRider = ref(null);

const openDispatchDialog = (order) => {
  currentDispatchOrder.value = order;
  dispatchDialogVisible.value = true;
};

const filteredOrders = computed(() => {
  let result = ordersList.value;
  const statusMap = {
    'PendingDispatch': [0],
    'PendingAccept': [1],
    'Processing': [2, 3]
  };
  const targetStatus = statusMap[currentOrderTab.value];
  if (targetStatus) {
    result = result.filter((o) => targetStatus.includes(o.status));
  }
  return result;
});

const filteredRiders = computed(() => {
  if (currentRiderTab.value === 'All') return ridersList.value;
  const map = {
    'Working': ['busy'],
    'Resting': ['resting'],
    'Disabled': ['disabled']
  };
  const allowed = map[currentRiderTab.value] || [];
  return ridersList.value.filter((r) => allowed.includes(r.status));
});
</script>

<style scoped>
.dispatch-container {
  height: calc(100vh - 84px);
  display: flex;
  flex-direction: column;
  background-color: #f0f2f5;
  overflow: hidden;
}

/* 1. Top Bar */
.top-filter-bar {
  height: 56px;
  background: #fff;
  border-bottom: 1px solid #e4e7ed;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.02);
  z-index: 20;
}

/* 2. Main Content */
.main-content {
  flex: 1;
  display: flex;
  position: relative;
  overflow: hidden;
}

/* Left Map Area */
.map-wrapper {
  flex: 1;
  position: relative;
  background: #fcf9f2;
  overflow: hidden;
}

.map-view {
  width: 100%;
  height: 100%;
}

/* Map Controls */
.map-controls-panel {
  position: absolute;
  bottom: 24px;
  left: 24px;
  display: flex;
  align-items: center;
  gap: 16px;
  z-index: 10;
}

.control-group {
  background: #fff;
  border-radius: 8px;
  padding: 6px;
  display: flex;
  gap: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.c-btn {
  padding: 6px 16px;
  border-radius: 6px;
  font-size: 13px;
  cursor: pointer;
  background: #f5f7fa;
  color: #606266;
  font-weight: 500;
  transition: all 0.2s;
}

.c-btn.active {
  background: #2d8cf0;
  color: #fff;
}

.c-btn.red {
  background: #fef0f0;
  color: #f56c6c;
  border: 1px solid #fde2e2;
}

.c-btn.green {
  background: #f0f9eb;
  color: #67c23a;
  border: 1px solid #e1f3d8;
}

.c-btn.gray {
  background: #f0f2f5;
  color: #909399;
  border: 1px solid #dcdfe6;
  cursor: default;
}

.c-btn.blue {
  background: #ecf5ff;
  color: #409eff;
  border: 1px solid #d9ecff;
}

.no-auth-map {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #fcfcfd;
  background-image: radial-gradient(#e5e7eb 1px, transparent 1px);
  background-size: 20px 20px;
}

.no-auth-content {
  text-align: center;
  padding: 40px;
  background: rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(8px);
  border-radius: 16px;
  border: 1px solid rgba(234, 236, 239, 0.8);
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.03);
  max-width: 320px;
}

.lock-icon {
  margin-bottom: 24px;
  display: flex;
  justify-content: center;
  opacity: 0.8;
}

.no-auth-title {
  margin: 0 0 12px 0;
  color: #303133;
  font-size: 20px;
  font-weight: 600;
}

.no-auth-desc {
  margin: 0 0 20px 0;
  color: #909399;
  font-size: 14px;
  line-height: 1.6;
}

.no-auth-tip {
  display: inline-block;
  padding: 4px 12px;
  background: #f4f4f5;
  color: #a8abb2;
  font-size: 12px;
  border-radius: 4px;
  font-family: monospace;
}

.map-error-state {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #fefefe;
}

.error-content {
  text-align: center;
  padding: 40px;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.05);
  border: 1px solid #fde2e2;
  max-width: 320px;

  .error-icon {
    font-size: 48px;
    color: #F56C6C;
    margin-bottom: 20px;
  }

  .error-title {
    margin: 0 0 10px 0;
    color: #303133;
    font-size: 18px;
  }

  .error-desc {
    color: #909399;
    font-size: 14px;
    line-height: 1.6;
    margin-bottom: 24px;
  }
}

/* Right Panel */
.right-panel {
  width: 440px;
  background: #fff;
  border-left: 1px solid #e4e7ed;
  display: flex;
  flex-direction: column;
  box-shadow: -4px 0 16px rgba(0, 0, 0, 0.05);
  z-index: 30;
}
</style>
