<template>
  <div class="addlayer-form">
    <a-form
      ref="formRef"
      :model="addlayer"
      :labelCol="{ width: '75px' }"
      labelAlign="right"
      :rules="addlayerRules"
    >
      <a-form-item label="标题名称" name="title">
        <a-input v-model:value="addlayer.title" placeholder="请输入标题名称" />
      </a-form-item>
      <a-form-item label="样式名称" name="styleName">
        <a-input v-model:value="addlayer.styleName" placeholder="请输入样式名称" />
      </a-form-item>
      <a-form-item label="上传文件" name="sldPath">
        <a-upload
          v-model:fileList="tucengFileList"
          name="addlayer.styleName"
          list-type="picture-card"
          class="upload-dragger"
          :multiple="false"
          :maxCount="1"
          :show-upload-list="false"
          :before-upload="tucengBeforeUpload"
          :custom-request="tucengCustomRequest"
          accept=".sld"
        >
          <div>
            <PlusOutlined />
            <div class="ant-upload-text">上传图层样式</div>
          </div>
        </a-upload>
        <div style="position: relative; top: 5px" v-if="addlayer.sldName">
          {{ addlayer.sldName }}
          <DeleteOutlined @click="deleteTuceng" />
        </div>
      </a-form-item>
    </a-form>
  </div>
</template>
<script lang="ts" setup>
  import { ref, reactive, watch } from 'vue';
  import { useMessage } from '@/hooks/web/useMessage';
  import type { UploadProps } from 'ant-design-vue';
  import { message, Upload } from 'ant-design-vue';
  import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
  // api
  import { GeoStyleAdd } from '@/api/demo/system';
  import axios from 'axios';
  import { cloneDeep } from 'lodash-es';
  import { getAppEnvConfig } from '@/utils/env';
  const { VITE_GLOB_API_URL } = getAppEnvConfig();
  const { createMessage } = useMessage();

  const emit = defineEmits(['addLayerSubmitAfter']);
  const props = defineProps(['layerStyleOptions']);

  const formRef = ref();
  // 默认
  const addlayerClone = {
    title: '',
    styleName: '',
    sldPath: '',
    sldName: '',
    style: '',
  };
  const addlayer = ref({
    title: '',
    styleName: '',
    sldPath: '',
    sldName: '',
    style: '',
  });

  // 验证
  const addlayerRules = reactive({
    title: [
      { required: true, message: '请输入标题名称', trigger: 'blur' },
      {
        validator: (rule, value, callback) => {
          let filter = Array.from(new Set(props.layerStyleOptions.map((item) => item.title)));
          if (filter.includes(value)) {
            callback(new Error('标题名称重复'));
          }
          callback();
        },
        trigger: 'blur',
      },
    ],
    styleName: [
      { required: true, message: '请输入样式名称', trigger: 'blur' },
      {
        validator: (rule, value, callback) => {
          let filter = Array.from(new Set(props.layerStyleOptions.map((item) => item.styleName)));
          if (filter.includes(value)) {
            callback(new Error('样式名称重复'));
          }
          callback();
        },
        trigger: 'blur',
      },
    ],
    sldPath: [{ required: true, message: '请上传图层样式', trigger: 'blur' }],
  });

  // 步骤1-图层样式上传
  const tucengFileList = ref<UploadProps['fileList']>([]);
  let isSldUpload = false;
  // 步骤1-图层上传之前
  const tucengBeforeUpload: UploadProps['beforeUpload'] = (file) => {
    let extension = file.name.substring(file.name.lastIndexOf('.') + 1);
    let size = file.size / 1024 / 1024;
    const isSld = extension === 'sld';
    const suitableSize = size < 1;
    if (!isSld) {
      createMessage.error('只能上传后缀是.sld的文件');
    }
    if (!suitableSize) {
      createMessage.error('文件大小不得超过1M');
    }
    isSldUpload = isSld && suitableSize;
    return isSldUpload;
  };
  // 步骤1-图层上传文件接口
  const tucengCustomRequest = (options) => {
    if (isSldUpload) {
      const formData = new FormData();
      readAndParseSLDFile(options.file);
      formData.append('files', options.file);
      // 假设 Token 存储在 localStorage 中
      const token = localStorage.getItem('X-Token');
      // 设置请求头部，带上 Token
      const headers = {
        'X-Token': token,
      };

      axios
        .post(VITE_GLOB_API_URL + '/api/Files/Upload', formData, { headers })
        .then((response) => {
          options.onSuccess(response.data, options.file);
          let fileName = response.data.result[0].fileName;
          let subFileName = fileName.substring(0, fileName.lastIndexOf('.'));
          addlayer.value.title = addlayer.value.title || subFileName;
          addlayer.value.styleName = addlayer.value.styleName || subFileName;
          addlayer.value.sldName = fileName;
          addlayer.value.sldPath = response.data.result[0].filePath;
        })
        .catch((error) => {
          options.onError(error);
        });
    }
  };
  // 步骤1-删除图层样式
  const deleteTuceng = () => {
    addlayer.value.sldName = '';
    addlayer.value.sldPath = '';
  };

  // 读取文件内容
  const readAndParseSLDFile = async (file) => {
    const reader = new FileReader();
    reader.onload = (e) => {
      const sldContent = e.target.result;
      // addlayer.value.text = sldContent;
      const styles = parseSLD(sldContent);
      assemblyPaint(styles);
    };
    reader.onerror = (error) => {
      console.error('Error reading the file:', error);
    };
    reader.readAsText(file);
  };
  // 解析sld文件
  const parseSLD = (sldFileContent) => {
    const parser = new DOMParser();
    const xmlDoc = parser.parseFromString(sldFileContent, 'application/xml');
    const namedLayers = xmlDoc.querySelectorAll('NamedLayer');
    const styles: any = [];

    namedLayers?.forEach((namedLayer) => {
      const userStyles = namedLayer.querySelectorAll('UserStyle');
      userStyles?.forEach((userStyle) => {
        userStyle.children?.forEach((element) => {
          if (element && element.nodeName == 'se:FeatureTypeStyle') {
            element.children.forEach((featureTypeStyle) => {
              let style: any = {};
              const rules = featureTypeStyle.children;
              rules.forEach((rule) => {
                // se:Name
                if (rule.nodeName == 'se:Name') {
                  style.ruleName = rule.textContent;
                }

                // ogc:Filter
                if (rule.nodeName == 'ogc:Filter') {
                  const ogcFilter = rule.children;
                  if (ogcFilter[0].nodeName == 'ogc:PropertyIsEqualTo') {
                    ogcFilter[0].children.forEach((item) => {
                      if (item.nodeName == 'ogc:PropertyName') {
                        style.ogcPropertyName = item.textContent.toLowerCase();
                      }
                      if (item.nodeName == 'ogc:Literal') {
                        style.ogcLiteral = item.textContent;
                      }
                    });
                  }
                }

                // se:PolygonSymbolizer
                if (rule.nodeName == 'se:PolygonSymbolizer') {
                  const sePolygonSymbolizers = rule.children;
                  const fillParams: any = [];
                  const strokeParams: any = [];
                  sePolygonSymbolizers.forEach((sePolygonSymbolizer) => {
                    if (sePolygonSymbolizer.nodeName == 'se:Fill') {
                      const fills = sePolygonSymbolizer.children;
                      fills.forEach((fill) => {
                        if (fill.nodeName == 'se:SvgParameter') {
                          fillParams[fill.getAttribute('name')] = fill.textContent;
                        }
                      });
                    }
                    if (sePolygonSymbolizer.nodeName == 'se:Stroke') {
                      const fills = sePolygonSymbolizer.children;
                      fills.forEach((fill) => {
                        if (fill.nodeName == 'se:SvgParameter') {
                          strokeParams[fill.getAttribute('name')] = fill.textContent;
                        }
                      });
                    }
                  });
                  style.seFill = fillParams;
                  style.seStroke = strokeParams;
                  styles.push(style);
                }
              });
            });
          }
        });
      });
    });
    return styles;
  };
  // 生成paint
  const assemblyPaint = (styles) => {
    let result: any = {};
    // fill-opacity
    result['fill-opacity'] = styles[0].seFill['fill-opacity']
      ? parseFloat(styles[0].seFill['fill-opacity'])
      : 1;

    // fill-color
    let onlyFillColor: any = [];
    const fillColor = styles.map((style) => {
      const { ruleName, ogcPropertyName, ogcLiteral, seFill, seStroke } = style;
      onlyFillColor.push(seFill['fill']);
      if (ogcLiteral) {
        return [['==', ['get', ogcPropertyName], ogcLiteral], seFill['fill']];
      } else {
        return seFill['fill'];
      }
    });
    result['fill-color'] = ['case', ...fillColor.flat()];

    onlyFillColor = [...new Set(onlyFillColor)];
    if (onlyFillColor.length == 1) {
      result['fill-color'] = onlyFillColor[0];
    }

    // fill-outline-color
    let onlyFillOutlineColor: any = [];
    const fillOutlineColor = styles.map((style) => {
      const { ruleName, ogcPropertyName, ogcLiteral, seFill, seStroke } = style;
      onlyFillOutlineColor.push(seStroke['stroke']);
      if (ogcLiteral) {
        return [['==', ['get', ogcPropertyName], ogcLiteral], seStroke['stroke']];
      } else {
        return seStroke['stroke'];
      }
    });
    result['fill-outline-color'] = ['case', ...fillOutlineColor.flat()];

    onlyFillOutlineColor = [...new Set(onlyFillOutlineColor)];
    if (onlyFillOutlineColor.length == 1) {
      result['fill-outline-color'] = onlyFillOutlineColor[0];
    }
    // style
    addlayer.value.style = JSON.stringify(result);
  };

  // 上传图层提交
  function addLayerSubmit() {
    formRef.value.validate().then(() => {
      GeoStyleAdd(addlayer.value).then((res) => {
        if (res) {
          emit('addLayerSubmitAfter', addlayer.value);
        }
      });
    });
  }
  // 上传图层取消
  function addLayerCancel() {
    // 刷新数据
    addlayer.value = cloneDeep(addlayerClone);
    // 清除验证
    formRef.value.clearValidate();
  }

  defineExpose({
    addLayerSubmit,
    addLayerCancel,
  });
</script>
<style lang="less" scoped>
  .addlayer-form {
    margin-left: 10px;
    margin-right: 10px;
  }
</style>
