<script setup lang="ts">
import { MapAreaType, type MapPen, type MapPointInfo, MapPointType, type Rect } from '@api/map';
import type {
  BinLocationGroup,
  BinLocationsList,
  BinTaskItem,
  BinTaskOperation,
  StorageLocationInfo,
} from '@api/scene';
import type { EditorService } from '@core/editor.service';
import sTheme from '@core/theme.service';
import { isNil } from 'lodash-es';
import { computed, inject, type InjectionKey, type ShallowRef } from 'vue';

type Props = {
  token: InjectionKey<ShallowRef<EditorService>>;
  current?: string;
  storageLocations?: StorageLocationInfo[]; // 当前动作点绑定的库位信息
};
const props = defineProps<Props>();
const editor = inject(props.token)!;

const pen = computed<MapPen | undefined>(() => editor.value.getPenById(props.current));
const point = computed<MapPointInfo | null>(() => {
  const v = pen.value?.point;
  if (!v?.type) return null;
  return v;
});
const rect = computed<Partial<Rect>>(() => {
  if (isNil(point.value)) return {};
  const { x, y } = editor.value.getPointRect(pen.value!) ?? {};
  return { x, y };
});

const bindRobot = computed<string>(
  () =>
    point.value?.robots
      ?.map((v) => editor.value.getRobotById(v)?.label)
      .filter((v) => !!v)
      .join('、') ?? '',
);
const bindAction = computed<string>(
  () =>
    point.value?.actions
      ?.map((v) => editor.value.getPenById(v))
      .filter((v) => v?.point?.type === MapPointType.动作点)
      .map((v) => v?.label)
      .filter((v) => !!v)
      .join('、') ?? '',
);

const mapAreas = (type: MapAreaType): string => {
  const id = pen.value?.id;
  if (!id) return '';
  return editor.value
    .getBoundAreas(id, 'point', type)
    .map(({ label }) => label)
    .filter((v) => !!v)
    .join('、');
};
const coArea1 = computed<string>(() => mapAreas(MapAreaType.库区));
const coArea2 = computed<string>(() => mapAreas(MapAreaType.互斥区));

// 库位状态标签样式映射
const getStorageStatusTag = (location: StorageLocationInfo) => {
  const tags = [];

  if (location.is_occupied) {
    tags.push({ text: '已占用', color: 'error' });
  } else {
    tags.push({ text: '未占用', color: 'success' });
  }

  if (location.is_locked) {
    tags.push({ text: '已锁定', color: 'warning' });
  } else {
    tags.push({ text: '未锁定', color: 'success' });
  }

  if (location.is_disabled) {
    tags.push({ text: '已禁用', color: 'error' });
  } else {
    tags.push({ text: '未禁用', color: 'success' });
  }

  if (location.is_empty_tray) {
    tags.push({ text: '空托盘', color: 'success' });
  } else {
    tags.push({ text: '非空托盘', color: 'warning' });
  }

  return tags;
};

// 解析库位任务数据
const parseBinTask = (binTaskString: string): BinTaskItem[] => {
  try {
    return JSON.parse(binTaskString.replace(/\n/g, '').trim());
  } catch (error) {
    console.error('解析库位任务数据失败:', error);
    return [];
  }
};

// 获取任务中的所有操作
const getTaskOperations = (task: BinTaskItem) => {
  if (!task || typeof task !== 'object') return {};

  const operations: Record<string, BinTaskOperation> = {};

  // 遍历任务对象的所有属性，查找操作对象
  for (const [key, value] of Object.entries(task)) {
    if (value && typeof value === 'object' && 'operation' in value) {
      operations[key] = value as BinTaskOperation;
    }
  }

  return operations;
};

// 获取当前动作点对应的库位任务数据
const binTaskData = computed(() => {
  try {
    const rawData = editor.value.getBinLocationsList();

    if (!rawData || !point.value) return [];

    const currentPointName = pen.value?.label || pen.value?.id;
    if (!currentPointName) return [];

    // 获取库位组数据
    const binLocationGroups = Array.isArray(rawData)
      ? (rawData as BinLocationGroup[])
      : (rawData as BinLocationsList)?.binLocationsList;

    if (!binLocationGroups || !Array.isArray(binLocationGroups)) return [];

    const allBinLocations = binLocationGroups
      .filter((group) => group && Array.isArray(group.binLocationList))
      .flatMap((group) => group.binLocationList)
      .filter((item) => item && typeof item === 'object');

    return allBinLocations
      .filter((item) => item.pointName === currentPointName)
      .map((item) => {
        try {
          if (!item.property || !Array.isArray(item.property)) {
            return {
              instanceName: item.instanceName || '未知库位',
              binTasks: [],
            };
          }

          const binTaskProperty = item.property.find((prop) => prop && prop.key === 'binTask');
          return {
            instanceName: item.instanceName || '未知库位',
            binTasks: binTaskProperty && binTaskProperty.stringValue ? parseBinTask(binTaskProperty.stringValue) : [],
          };
        } catch (error) {
          console.error('处理库位任务数据失败:', error, item);
          return {
            instanceName: item.instanceName || '未知库位',
            binTasks: [],
          };
        }
      })
      .filter((item) => item.binTasks.length > 0);
  } catch (error) {
    console.error('获取库位任务数据失败:', error);
    return [];
  }
});
</script>

<template>
  <a-card :bordered="false">
    <template v-if="pen && point">
      <a-row :gutter="[8, 8]">
        <a-col :span="24">
          <a-flex align="center" :gap="8">
            <i class="icon point" />
            <a-typography-text class="card-title" style="flex: auto" :content="pen.label" ellipsis />
            <a-tag :bordered="false">{{ $t(MapPointType[point.type]) }}</a-tag>
          </a-flex>
        </a-col>

        <a-col :span="24">
          <a-typography-text code>{{ pen.desc || $t('暂无描述') }}</a-typography-text>
        </a-col>
      </a-row>

      <a-list class="block mt-16">
        <a-list-item>
          <a-typography-text type="secondary">{{ $t('站点坐标') }}</a-typography-text>
          <a-typography-text>({{ rect.x?.toFixed() }},{{ rect.y?.toFixed() }})</a-typography-text>
        </a-list-item>
        <a-list-item v-if="point.type === MapPointType.自动门点 && point.deviceId">
          <a-typography-text type="secondary">{{ $t('设备ID') }}</a-typography-text>
          <a-typography-text>{{ point.deviceId }}</a-typography-text>
        </a-list-item>
        <a-list-item v-if="point.type === MapPointType.自动门点">
          <a-typography-text type="secondary">{{ $t('连接状态') }}</a-typography-text>
          <a-flex align="center" :gap="8" class="conn-status">
            <span
              class="status-dot"
              :class="point.isConnected ? 'online' : 'offline'"
              :title="point.isConnected ? $t('已连接') : $t('未连接')"
            />
            <a-typography-text>
              {{ point.isConnected ? $t('已连接') : $t('未连接') }}
            </a-typography-text>
          </a-flex>
        </a-list-item>
        <a-list-item v-if="point.extensionType">
          <a-typography-text type="secondary">{{ $t('扩展类型') }}</a-typography-text>
          <a-typography-text>{{ $t(MapPointType[point.extensionType]) }}</a-typography-text>
        </a-list-item>
        <a-list-item v-if="[MapPointType.充电点, MapPointType.停靠点].includes(point.type)">
          <a-flex :gap="8" vertical>
            <a-typography-text type="secondary">{{ $t('绑定机器人') }}</a-typography-text>
            <a-typography-text>{{ bindRobot || $t('暂无') }}</a-typography-text>
          </a-flex>
        </a-list-item>
        <a-list-item v-if="point.type === MapPointType.停靠点">
          <a-typography-text type="secondary">{{ $t('启用状态') }}</a-typography-text>
          <a-typography-text>{{ point.enabled === 1 ? $t('已启用') : $t('已禁用') }}</a-typography-text>
        </a-list-item>
        <a-list-item v-if="MapPointType.等待点 === point.type">
          <a-flex :gap="8" vertical>
            <a-typography-text type="secondary">{{ $t('绑定动作点') }}</a-typography-text>
            <a-typography-text>{{ bindAction || $t('暂无') }}</a-typography-text>
          </a-flex>
        </a-list-item>
        <a-list-item v-if="MapPointType.动作点 === point.type">
          <a-flex :gap="8" vertical>
            <a-typography-text type="secondary">{{ $t('关联库区') }}</a-typography-text>
            <a-typography-text>{{ coArea1 || $t('暂无') }}</a-typography-text>
          </a-flex>
        </a-list-item>
        <a-list-item v-if="MapPointType.动作点 === point.type && point.associatedStorageLocations?.length">
          <a-flex :gap="8" vertical>
            <a-typography-text type="secondary">{{ $t('库位') }}</a-typography-text>
            <a-typography-text>{{ point.associatedStorageLocations.join('、') }}</a-typography-text>
          </a-flex>
        </a-list-item>
        <a-list-item
          v-if="
            [
              MapPointType.普通点,
              MapPointType.电梯点,
              MapPointType.自动门点,
              MapPointType.等待点,
              MapPointType.充电点,
              MapPointType.停靠点,
              MapPointType.动作点,
              MapPointType.临时避让点,
            ].includes(point.type)
          "
        >
          <a-flex :gap="8" vertical>
            <a-typography-text type="secondary">{{ $t('关联互斥区') }}</a-typography-text>
            <a-typography-text>{{ coArea2 || $t('暂无') }}</a-typography-text>
          </a-flex>
        </a-list-item>
        <a-list-item v-if="MapPointType.动作点 === point.type && storageLocations?.length">
          <a-flex :gap="8" vertical>
            <a-typography-text type="secondary">{{ $t('库位状态') }}</a-typography-text>
            <div class="storage-locations">
              <div v-for="location in storageLocations" :key="location.id" class="storage-item">
                <a-typography-text class="storage-name">{{ location.layer_name }}</a-typography-text>
                <div class="storage-tags">
                  <div
                    v-for="tag in getStorageStatusTag(location)"
                    :key="tag.text"
                    :class="['storage-tag', `storage-tag-${tag.color}`]"
                  >
                    {{ tag.text }}
                  </div>
                </div>
              </div>
            </div>
          </a-flex>
        </a-list-item>
        <a-list-item v-if="MapPointType.动作点 === point.type && binTaskData.length">
          <a-flex :gap="8" vertical>
            <a-typography-text type="secondary">{{ $t('库位任务配置') }}</a-typography-text>
            <div class="bin-task-container">
              <div v-for="binLocation in binTaskData" :key="binLocation.instanceName" class="bin-task-group">
                <a-typography-text class="bin-location-name">{{ binLocation.instanceName }}</a-typography-text>
                <div class="bin-tasks">
                  <div v-for="(task, taskIndex) in binLocation.binTasks" :key="taskIndex" class="bin-task-item">
                    <div
                      v-for="(operation, operationType) in getTaskOperations(task)"
                      :key="operationType"
                      class="task-operation"
                    >
                      <a-typography-text class="operation-title">
                        {{ operationType }}
                      </a-typography-text>
                      <div class="operation-summary">
                        <span class="operation-type">{{ operation.operation || '未知操作' }}</span>
                        <div class="operation-tooltip">
                          <i class="icon detail" />
                          <div class="tooltip-content">
                            <div v-for="(value, key) in operation" :key="key" class="detail-item">
                              <span class="detail-key">{{ key }}:</span>
                              <span class="detail-value">
                                {{ typeof value === 'boolean' ? (value ? '是' : '否') : (value ?? '未知') }}
                              </span>
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </a-flex>
        </a-list-item>
      </a-list>
    </template>
    <a-empty v-else :image="sTheme.empty" />
  </a-card>
</template>

<style scoped lang="scss">
@use '/src/assets/themes/theme' as *;

@include themed {
  .conn-status {
    .status-dot {
      width: 8px;
      height: 8px;
      border-radius: 50%;
      display: inline-block;
      box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.05);
      &.online {
        background-color: get-color(success);
        box-shadow: 0 0 0 2px rgba(82, 196, 26, 0.15);
      }
      &.offline {
        background-color: get-color(error);
        box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.15);
      }
    }
  }

  .storage-locations {
    .storage-item {
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 8px;
      padding: 16px;
      border-radius: 4px;

      &:last-child {
        margin-bottom: 0;
      }

      .storage-name {
        font-weight: 500;
        flex-shrink: 0;
        margin-right: 8px;
        color: get-color(text1);
      }

      .storage-tags {
        flex: 1;
        display: flex;
        flex-wrap: wrap;
        justify-content: flex-end;
        gap: 4px;
      }

      .storage-tag {
        padding: 2px 6px;
        font-size: 12px;
        border-radius: 4px;
        border: 1px solid;

        &-error {
          color: get-color(error_text);
          background-color: get-color(error_bg);
          border-color: get-color(error_border);
        }

        &-success {
          color: get-color(success_text);
          background-color: get-color(success_bg);
          border-color: get-color(success_border);
        }

        &-warning {
          color: get-color(warning_text);
          background-color: get-color(warning_bg);
          border-color: get-color(warning_border);
        }

        &-processing {
          color: get-color(primary_text);
          background-color: get-color(primary_bg);
          border-color: get-color(primary_border);
        }

        &-default {
          color: get-color(text2);
          background-color: get-color(fill2);
          border-color: get-color(border1);
        }
      }
    }
  }

  .bin-task-container {
    .bin-task-group {
      margin-bottom: 16px;
      padding: 12px;
      border-radius: 4px;
      background-color: get-color(fill4);

      &:last-child {
        margin-bottom: 0;
      }

      .bin-location-name {
        font-weight: 600;
        color: get-color(text1);
        margin-bottom: 8px;
        display: block;
      }

      .bin-tasks {
        .bin-task-item {
          margin-bottom: 12px;

          &:last-child {
            margin-bottom: 0;
          }

          .task-operation {
            margin-bottom: 8px;
            padding: 8px;
            border-radius: 4px;
            background-color: get-color(fill4);

            &:last-child {
              margin-bottom: 0;
            }

            .operation-title {
              font-weight: 500;
              color: get-color(primary);
              margin-bottom: 6px;
              display: block;
            }

            .operation-summary {
              display: flex;
              align-items: center;
              gap: 8px;
              cursor: pointer;

              .operation-type {
                font-weight: 500;
                color: get-color(primary);
                flex-shrink: 0;
              }

              .operation-tooltip {
                position: relative;
                display: inline-block;

                .icon.detail {
                  width: 14px;
                  height: 14px;
                  background-image: url('/src/assets/icons/dark/detail.png');
                  background-size: contain;
                  background-repeat: no-repeat;
                  background-position: center;
                  cursor: pointer;
                  opacity: 0.6;
                  transition: opacity 0.2s ease;

                  &:hover {
                    opacity: 1;
                  }
                }

                @media (prefers-color-scheme: light) {
                  .icon.detail {
                    background-image: url('/src/assets/icons/light/detail.png');
                  }
                }

                .tooltip-content {
                  position: absolute;
                  bottom: 100%;
                  left: 50%;
                  transform: translateX(-50%);
                  background-color: get-color(fill1);
                  color: get-color(text1);
                  padding: 8px;
                  border-radius: 4px;
                  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
                  z-index: 1000;
                  white-space: nowrap;
                  font-size: 12px;
                  line-height: 1.5;
                  max-width: 200px;
                  word-break: break-all;
                  border: 1px solid get-color(border1);
                  opacity: 0;
                  visibility: hidden;
                  transition:
                    opacity 0.2s ease,
                    visibility 0.2s ease;
                  backdrop-filter: blur(8px);
                  -webkit-backdrop-filter: blur(8px);
                  background: get-color(fill1) !important;
                }

                &:hover .tooltip-content {
                  opacity: 1;
                  visibility: visible;
                }

                .detail-item {
                  display: flex;
                  justify-content: space-between;
                  margin-bottom: 4px;

                  &:last-child {
                    margin-bottom: 0;
                  }

                  .detail-key {
                    color: get-color(text2);
                    font-weight: 500;
                    flex-shrink: 0;
                    margin-right: 8px;
                  }

                  .detail-value {
                    color: get-color(text1);
                    text-align: right;
                    word-break: break-all;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
</style>
