<template>
  <div class="p-2">
    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
      <div v-show="showSearch" class="mb-[10px]">
        <el-card shadow="hover">
          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="100px">
            <el-form-item label="用户信息" prop="params.userKeyword">
              <el-input v-model="queryParams.params.userKeyword" placeholder="请输入用户名或手机号" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="设备编号" prop="serialNum">
              <el-input v-model="queryParams.serialNum" placeholder="请输入设备编号" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="设备名称" prop="deviceName">
              <el-input v-model="queryParams.deviceName" placeholder="请输入设备名称" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="塘口名称" prop="params.pondKeyword">
              <el-input v-model="queryParams.params.pondKeyword" placeholder="请输入塘口名称" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="在线状态" prop="params.onlineStatus">
              <el-select v-model="queryParams.params.onlineStatus" placeholder="请选择在线状态" clearable style="width: 180px" @change="handleQuery">
                <el-option v-for="item in onlineStatusOptions" :key="item.value" :label="item.label" :value="item.value" />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
            </el-form-item>
          </el-form>
        </el-card>
      </div>
    </transition>

    <el-card shadow="never">
      <template #header>
        <el-row :gutter="10" class="mb8">
          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
        </el-row>
      </template>

      <el-table v-loading="loading" border :data="deviceList" row-key="id">
        <el-table-column label="用户名" align="center" prop="userName" min-width="120" />
        <el-table-column label="手机号" align="center" prop="mobilePhone" min-width="120" />
        <el-table-column label="设备编号" align="center" prop="serialNum" min-width="150" />
        <el-table-column label="设备名称" align="center" prop="deviceName" min-width="130" />
        <el-table-column label="塘口名称" align="center" prop="pondName" min-width="120" />
        <el-table-column label="在线状态" align="center" width="120">
          <template #default="scope">
            <el-tag :type="getStatusTagType(scope.row)" effect="light">
              {{ getStatusText(scope.row) }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="盐度补偿" align="center" prop="salinityCompensation" width="120">
          <template #default="scope">
            {{ formatValue(scope.row.salinityCompensation) }}
          </template>
        </el-table-column>
        <!-- <el-table-column label="线性补偿" align="center" prop="phaseCompensation" width="120">
          <template #default="scope">
            {{ formatValue(scope.row.phaseCompensation) }}
          </template>
        </el-table-column>
        <el-table-column label="相位差补偿" align="center" prop="phasedifCompensation" width="120">
          <template #default="scope">
            {{ formatValue(scope.row.phasedifCompensation) }}
          </template>
        </el-table-column>
        <el-table-column label="温度补偿" align="center" prop="temperatureCompensation" width="120">
          <template #default="scope">
            {{ formatValue(scope.row.temperatureCompensation) }}
          </template>
        </el-table-column> -->
        <el-table-column label="最后上数时间" align="center" prop="lastReportTime" min-width="170">
          <template #default="scope">
            <span>{{ parseTime(scope.row.lastReportTime, '{y}-{m}-{d} {h}:{i}:{s}') || '-' }}</span>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" fixed="right" width="260">
          <template #default="scope">
            <el-button link type="primary" icon="Refresh" :loading="statusLoadingId === scope.row.id" @click="refreshStatus(scope.row)">刷新状态</el-button>
            <el-button link type="primary" icon="Position" @click="openCommand(scope.row)" v-hasPermi="['fishery:solarControl:command']">下发指令</el-button>
          </template>
        </el-table-column>
      </el-table>

      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    </el-card>

    <el-dialog v-model="commandOpen" :title="commandTitle" width="680px" append-to-body destroy-on-close>
      <template v-if="currentDevice">
        <div class="device-summary">
          <div>
            <div class="device-summary__name">{{ currentDevice.deviceName || '-' }}</div>
            <div class="device-summary__serial">{{ currentDevice.serialNum }}</div>
          </div>
          <el-tag :type="getStatusTagType(currentDevice)" size="large">{{ getStatusText(currentDevice) }}</el-tag>
        </div>

        <el-form ref="commandFormRef" :model="commandForm" :rules="commandRules" label-width="130px">
          <el-form-item label="下发属性" prop="identifier">
            <el-select v-model="commandForm.identifier" filterable placeholder="请选择属性" style="width: 100%" @change="handlePropertyChange">
              <el-option-group v-for="group in propertyGroups" :key="group.label" :label="group.label">
                <el-option v-for="item in group.options" :key="item.identifier" :label="item.name" :value="item.identifier">
                  <span>{{ item.name }}</span>
                  <span class="property-option-code">{{ item.identifier }}</span>
                </el-option>
              </el-option-group>
            </el-select>
          </el-form-item>

          <template v-if="selectedProperty">
            <el-form-item v-if="selectedProperty.type === 'enum'" :label="selectedProperty.name" prop="value">
              <el-select v-model="commandForm.value" placeholder="请选择值" style="width: 100%">
                <el-option v-for="option in selectedProperty.options" :key="String(option.value)" :label="option.label" :value="option.value" />
              </el-select>
            </el-form-item>

            <template v-else-if="selectedProperty.type === 'struct'">
              <el-form-item
                v-for="field in selectedProperty.fields"
                :key="field.identifier"
                :label="field.name"
                :prop="`structValue.${field.identifier}`"
                :rules="[{ required: true, message: `${field.name}不能为空`, trigger: 'blur' }]"
              >
                <el-input-number
                  v-model="commandForm.structValue[field.identifier]"
                  :min="field.min"
                  :max="field.max"
                  :step="field.step"
                  :precision="field.precision"
                  controls-position="right"
                  style="width: 100%"
                />
              </el-form-item>
            </template>

            <el-form-item v-else :label="selectedProperty.name" prop="value">
              <el-input-number
                v-model="commandForm.value"
                :min="selectedProperty.min"
                :max="selectedProperty.max"
                :step="selectedProperty.step"
                :precision="selectedProperty.precision"
                controls-position="right"
                style="width: 100%"
              />
            </el-form-item>

            <div class="property-meta">
              <span>{{ selectedProperty.identifier }}</span>
              <span v-if="selectedProperty.rangeText">{{ selectedProperty.rangeText }}</span>
              <span v-if="selectedProperty.unit">{{ selectedProperty.unit }}</span>
            </div>
          </template>
        </el-form>
      </template>

      <template #footer>
        <div class="command-footer">
          <el-button @click="commandOpen = false">取消</el-button>
          <el-button type="primary" icon="Position" :loading="submitLoading" @click="submitCommand">下发</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup name="SolarControl" lang="ts">
import { listSolarDevice } from '@/api/fishery/device';
import { DeviceQuery, DeviceVO } from '@/api/fishery/device/types';
import { getDeviceStatus, sendSolarPropertyCommand } from '@/api/iot';

type PropertyType = 'float' | 'double' | 'int' | 'enum' | 'struct';

interface PropertyOption {
  identifier: string;
  name: string;
  type: PropertyType;
  min?: number;
  max?: number;
  step?: number;
  precision?: number;
  unit?: string;
  rangeText?: string;
  options?: Array<{ label: string; value: number }>;
  fields?: Array<Required<Pick<PropertyOption, 'identifier' | 'name' | 'min' | 'max' | 'step' | 'precision'>> & { unit?: string }>;
  defaultValue?: number;
}

interface SolarDeviceVO extends DeviceVO {
  online?: boolean;
  statusCode?: number;
}

const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const queryFormRef = ref<ElFormInstance>();
const commandFormRef = ref<ElFormInstance>();

const deviceList = ref<SolarDeviceVO[]>([]);
const loading = ref(false);
const showSearch = ref(true);
const total = ref(0);
const commandOpen = ref(false);
const currentDevice = ref<SolarDeviceVO>();
const submitLoading = ref(false);
const statusLoadingId = ref<string | number>();

const onlineStatusOptions = [
  { label: '在线', value: 'online' },
  { label: '离线', value: 'offline' }
];

const data = reactive<PageData<{}, DeviceQuery>>({
  form: {},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    serialNum: undefined,
    deviceName: undefined,
    deviceType: 3,
    params: {
      userKeyword: undefined,
      onlineStatus: undefined,
      pondKeyword: undefined
    }
  },
  rules: {}
});

const { queryParams } = toRefs(data);

const propertyGroups = [
  {
    label: '常用设置',
    options: [
      numberProperty('salinitySet', '盐度设置', 'float', 0, 100, 0.01, undefined, 0),
      enumProperty('PowerMode', '电源模式', {
        0: '太阳能网控常驻模式',
        1: '太阳能网控节能模式',
        2: '适配器网控'
      }),
      numberProperty('WakeUpTime', '休眠时长', 'int', 1, 2147483647, 1, 'min', 10),
      numberProperty('BootToSleepTimeout', '工作时长', 'int', 2, 2147483647, 1, 'min', 2),
      numberProperty('updatatime', '数据上报时间', 'int', 0, 65535, 1, 's', 60),
      numberProperty('FirstBootToSleepTimeout', '首次上电工作时间', 'int', 3, 2147483647, 1, 'min', 3)
    ]
  },
  {
    label: '校准与补偿',
    options: [
      enumProperty('correct', '校准', {
        1: '下发溶解氧传感器校准指令',
        2: '下发盐度传感器校准指令',
        11: '氧探头饱和校准',
        12: '氧探头无氧校准',
        13: '氧探头低温系数设置',
        14: '氧探头高温系数设置',
        31: '下发pH传感器校准第1步',
        32: '下发pH传感器校准第2步'
      }),
      numberProperty('phasedif_compensation', '相位差补偿', 'float', -10, 100, 0.001, '°', 0),
      numberProperty('phase_compensation', '线性补偿', 'float', 0, 10, 0.0001, undefined, 1),
      numberProperty('temperature_compensation', '温度补偿', 'float', -10, 10, 0.001, '°C', 0),
      numberProperty('stdsatphase', '标准饱和相位差', 'double', 0, 360, 0.01, '°', 0),
      numberProperty('stdphaseinterval', '标准相位区间', 'double', 0, 360, 0.01, '°', 0)
    ]
  },
  {
    label: '高级参数',
    options: [
      numberProperty('SaturationPoint', '饱和相位差测量值', 'float', -1000, 1000, 0.01, '°', 0),
      numberProperty('AnaerobicPoint', '无氧相位差测量值', 'float', -1000, 1000, 0.01, '°', 0),
      numberProperty('LowtempCOEF', '低温系数', 'float', -1000, 1000, 0.0001, undefined, 0),
      numberProperty('HightempCOEF', '高温系数', 'float', -1000, 1000, 0.0001, undefined, 0),
      numberProperty('ammonia_nitrogen', '氨氮', 'float', 0, 1000, 0.01, 'mg/L', 0),
      numberProperty('TempPobeOffSet1', '温度偏移量通道1', 'float', -12.7, 12.7, 0.1, '°C', 0),
      numberProperty('TempPobeOffSet2', '温度偏移量通道2', 'float', -12.7, 12.7, 1, '°C', 0),
      structProperty('CorrectCharge', '电量校准', [
        numberProperty('lowvoltage', '低压', 'float', 0, 10, 0.01, 'V', 0),
        numberProperty('highvoltage', '高压', 'float', 0, 10, 0.01, 'V', 0)
      ])
    ]
  }
];

const propertyList = computed(() => propertyGroups.flatMap((group) => group.options));
const selectedProperty = computed(() => propertyList.value.find((item) => item.identifier === commandForm.identifier));
const commandTitle = computed(() => `太阳能网控指令 - ${currentDevice.value?.deviceName || ''}`);

const commandForm = reactive({
  identifier: 'PowerMode',
  value: undefined as number | undefined,
  structValue: {} as Record<string, number | undefined>
});

const commandRules = {
  identifier: [{ required: true, message: '请选择下发属性', trigger: 'change' }],
  value: [{ required: true, message: '属性值不能为空', trigger: 'blur' }]
};

function numberProperty(
  identifier: string,
  name: string,
  type: Extract<PropertyType, 'float' | 'double' | 'int'>,
  min: number,
  max: number,
  step: number,
  unit?: string,
  defaultValue?: number
): PropertyOption {
  return {
    identifier,
    name,
    type,
    min,
    max,
    step,
    unit,
    precision: getPrecision(step),
    rangeText: `${min} - ${max}`,
    defaultValue
  };
}

function enumProperty(identifier: string, name: string, options: Record<number, string>): PropertyOption {
  const values = Object.entries(options).map(([value, label]) => ({ value: Number(value), label }));
  return {
    identifier,
    name,
    type: 'enum',
    options: values,
    defaultValue: values[0]?.value
  };
}

function structProperty(identifier: string, name: string, fields: PropertyOption[]): PropertyOption {
  return {
    identifier,
    name,
    type: 'struct',
    fields: fields.map((field) => ({
      identifier: field.identifier,
      name: field.name,
      min: field.min ?? 0,
      max: field.max ?? 0,
      step: field.step ?? 1,
      precision: field.precision ?? 0,
      unit: field.unit
    }))
  };
}

function getPrecision(step: number) {
  const text = String(step);
  if (!text.includes('.')) {
    return 0;
  }
  return text.split('.')[1].length;
}

const getList = async () => {
  loading.value = true;
  try {
    queryParams.value.deviceType = 3;
    const res = await listSolarDevice(queryParams.value);
    deviceList.value = ((res.rows || []) as SolarDeviceVO[]).map(initStatusFromList);
    total.value = res.total;
    await refreshVisibleStatuses();
    sortDeviceListByOnline();
  } finally {
    loading.value = false;
  }
};

const initStatusFromList = (item: SolarDeviceVO) => {
  if (item.onlineStatus?.toLowerCase() === 'online') {
    item.online = true;
    item.statusCode = 1;
  } else {
    item.online = false;
    item.statusCode = 3;
  }
  return item;
};

const refreshVisibleStatuses = async () => {
  await Promise.all(
    deviceList.value.map(async (item) => {
      try {
        await refreshStatus(item, false);
      } catch {
        // 列表已有后端状态，单台云端状态刷新失败时不影响整页展示。
      }
    })
  );
};

const refreshStatus = async (row: SolarDeviceVO, showMessage = true) => {
  if (!row.serialNum) {
    row.online = false;
    row.statusCode = 0;
    return;
  }
  statusLoadingId.value = row.id;
  try {
    const res = await getDeviceStatus(3, row.serialNum);
    row.statusCode = res.data;
    row.online = res.data === 1;
    if (currentDevice.value?.id === row.id) {
      currentDevice.value = row;
    }
    sortDeviceListByOnline();
    if (showMessage) {
      ElMessage.success('状态已刷新');
    }
  } finally {
    statusLoadingId.value = undefined;
  }
};

const handleQuery = () => {
  queryParams.value.pageNum = 1;
  getList();
};

const resetQuery = () => {
  queryFormRef.value?.resetFields();
  queryParams.value.deviceType = 3;
  queryParams.value.params = {
    userKeyword: undefined,
    onlineStatus: undefined,
    pondKeyword: undefined
  };
  getList();
};

const openCommand = async (row: SolarDeviceVO) => {
  currentDevice.value = row;
  resetCommandForm();
  commandOpen.value = true;
  await refreshStatus(row, false);
};

const resetCommandForm = () => {
  commandForm.identifier = 'PowerMode';
  handlePropertyChange('PowerMode');
  nextTick(() => commandFormRef.value?.clearValidate());
};

const handlePropertyChange = (identifier: string) => {
  const property = propertyList.value.find((item) => item.identifier === identifier);
  commandForm.value = property?.defaultValue;
  commandForm.structValue = {};
  if (property?.type === 'struct') {
    property.fields?.forEach((field) => {
      commandForm.structValue[field.identifier] = 0;
    });
  }
};

const submitCommand = async () => {
  if (!currentDevice.value || !selectedProperty.value) {
    return;
  }
  await commandFormRef.value?.validate();
  const property = selectedProperty.value;
  const value = property.type === 'struct' ? { ...commandForm.structValue } : commandForm.value;
  submitLoading.value = true;
  try {
    await sendSolarPropertyCommand({
      id: currentDevice.value.id,
      properties: {
        [property.identifier]: value
      }
    });
    ElMessage.success('下发成功');
    commandOpen.value = false;
    await getList();
  } finally {
    submitLoading.value = false;
  }
};

const getStatusText = (row: SolarDeviceVO) => {
  if (row.online) {
    return '在线';
  }
  if (row.statusCode === 3) {
    return '离线';
  }
  if (row.statusCode === 8) {
    return '禁用';
  }
  if (row.statusCode === 0) {
    return '未激活';
  }
  return '未知';
};

const getStatusTagType = (row: SolarDeviceVO) => {
  if (row.online) {
    return 'success';
  }
  if (row.statusCode === 3) {
    return 'warning';
  }
  if (row.statusCode === 8) {
    return 'danger';
  }
  return 'info';
};

const formatValue = (value: unknown) => {
  if (value === undefined || value === null || value === '') {
    return '-';
  }
  return value;
};

const sortDeviceListByOnline = () => {
  deviceList.value = deviceList.value
    .map((item, index) => ({ item, index }))
    .sort((a, b) => {
      const onlineDiff = Number(Boolean(b.item.online)) - Number(Boolean(a.item.online));
      if (onlineDiff !== 0) {
        return onlineDiff;
      }
      return a.index - b.index;
    })
    .map(({ item }) => item);
};

onMounted(() => {
  getList();
});
</script>

<style scoped lang="scss">
.device-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 14px;
  margin-bottom: 12px;
  background: #f6f8fb;
  border: 1px solid #e4e7ed;
  border-radius: 6px;
}

.device-summary__name {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.device-summary__serial {
  margin-top: 4px;
  font-size: 13px;
  color: #606266;
}

.property-option-code {
  float: right;
  margin-left: 16px;
  color: #909399;
  font-size: 12px;
}

.property-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-left: 130px;
  margin-bottom: 16px;
  color: #909399;
  font-size: 12px;
}

.command-footer {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
</style>
