<!--
 * 文件说明：HTTP 节点参数面板，配置请求及输出字段。
 * 作用范围：仅服务于流程设计器模块。
 -->
<template>
    <el-form :inline="true" :model="httpNodeData" :rules="rules" class="http-form" ref="dynamicFormRef"
        label-position="top" label-width="auto">
        <el-collapse v-model="activeNames">
            <el-collapse-item name="1" icon-position="left">
                <template #title>
                    请求配置
                    <el-tooltip class="box-item" effect="dark" content="支持HTTP/HTTPS协议" placement="top">
                        <el-icon class="header-icon" style="margin-left: 6px">
                            <info-filled />
                        </el-icon>
                    </el-tooltip>
                </template>
                <div class="form__container">
                    <div v-for="(property, index) in httpNodeData.config" :key="index">
                        <el-row>
                            <el-form-item :label="index === 0 ? '参数名' : ''" :prop="`config.${index}.name`" :rules="[
                                { required: true, message: '请输入参数名', trigger: 'blur' },
                            ]">
                                <el-input :disabled="true" class="param-name" v-model="property.name" placeholder="请输入"
                                    clearable />
                            </el-form-item>
                            <el-form-item :label="index === 0 ? '参数值' : ''" :prop="`config.${index}.input`">
                                <el-select v-model="property.type" class="param-type" @change="handleTypeChange(index)">
                                    <el-option label="引用" value="quote" />
                                    <el-option label="输入" value="input" />
                                </el-select>
                                <el-form-item v-if="property.type === 'input'" :rules="[
                                    {
                                        required: property?.required ?? true,
                                        message: '请输入参数值',
                                        trigger: 'blur',
                                    },
                                ]" :prop="`config.${index}.input`">
                                    <el-input-number class="param-value" v-if="property.componentType === 'number'"
                                        v-model="property.input" :min="0" :max="property.max || Infinity"
                                        :controls="false" :step-strictly="true" placeholder="请输入" clearable />
                                    <el-select v-model="property.input" class="param-value"
                                        v-else-if="property.componentType === 'select'">
                                        <el-option v-for="item in property.selectOptions" :key="item.value"
                                            :label="item.label" :value="item.value" />
                                    </el-select>
                                    <el-input class="param-value" v-else v-model="property.input" placeholder="请输入"
                                        clearable />
                                </el-form-item>
                                <el-form-item v-if="property.type === 'quote'" :rules="[
                                    {
                                        required: true,
                                        message: '请选择参数值',
                                        trigger: 'blur',
                                    },
                                ]" :prop="`config.${index}.quote`">
                                    <el-cascader :ref="(el) => {
                                            if (el) cascaderRefs[index] = el;
                                        }
                                        " v-model="property.quote" :checkStrictly="true" :options="quoteOptions" placeholder="请选择"
                                        @visible-change="
                                            (visible) => visibleChange(visible, index, property.quote)
                                        " @change="(value) => cascaderChange(value, index, httpNodeData, 'config')" />
                                </el-form-item>
                            </el-form-item>
                        </el-row>
                    </div>
                </div>
            </el-collapse-item>
            <el-collapse-item name="2" icon-position="left">
                <template #title>
                    Header配置
                    <el-button :circle="true" size="small" @click="(e) => addHttpNodeFormItem(e, 'headers')"
                        class="addFormItem">
                        <el-icon :size="14">
                            <Plus />
                        </el-icon>
                    </el-button>
                </template>
                <div class="form__container">
                    <div v-for="(property, index) in httpNodeData.headers" :key="index">
                        <el-row>
                            <el-form-item :label="index === 0 ? '参数名' : ''"
                                :prop="httpNodeData.headers.length > index ? `headers.${index}.name` : undefined"
                                :rules="[
                                    { required: true, message: '请输入参数名', trigger: 'blur' },
                                ]">
                                <el-input class="param-name" v-model="property.name" placeholder="请输入" clearable />
                            </el-form-item>
                            <el-form-item :label="index === 0 ? '参数值' : ''"
                                :prop="httpNodeData.headers.length > index ? `headers.${index}.input` : undefined">
                                <el-select v-model="property.type" class="param-type" @change="handleTypeChange(index)">
                                    <el-option label="引用" value="quote" />
                                    <el-option label="输入" value="input" />
                                </el-select>
                                <el-form-item v-if="property.type === 'input'" :rules="[
                                    {
                                        required: property?.required ?? true,
                                        message: '请输入参数值',
                                        trigger: 'blur',
                                    },
                                ]" :prop="`headers.${index}.input`">
                                    <el-input-number class="param-value" v-if="property.componentType === 'number'"
                                        v-model="property.input" :min="0" :max="property.max || Infinity"
                                        :controls="false" :step-strictly="true" placeholder="请输入" clearable />
                                    <el-select v-model="property.input" class="param-value"
                                        v-else-if="property.componentType === 'select'">
                                        <el-option v-for="item in property.selectOptions" :key="item.value"
                                            :label="item.label" :value="item.value" />
                                    </el-select>
                                    <el-input class="param-value" v-else v-model="property.input" placeholder="请输入"
                                        clearable />
                                </el-form-item>
                                <el-form-item v-if="property.type === 'quote'" :rules="[
                                    {
                                        required: true,
                                        message: '请选择参数值',
                                        trigger: 'blur',
                                    },
                                ]" :prop="`headers.${index}.quote`">
                                    <el-cascader :ref="(el) => {
                                            if (el) cascaderRefs[index] = el;
                                        }
                                        " v-model="property.quote" :checkStrictly="true" :options="quoteOptions" placeholder="请选择"
                                        @visible-change="
                                            (visible) => visibleChange(visible, index, property.quote)
                                        " @change="(value) => cascaderChange(value, index, httpNodeData, 'headers')" />
                                </el-form-item>
                            </el-form-item>
                            <el-button :icon="Minus" circle size="small" @click="handleHttpNodeDelete('headers', index)"
                                class="deleteBtn" />
                        </el-row>
                    </div>
                </div>
            </el-collapse-item>
            <el-collapse-item name="3" icon-position="left">
                <template #title>
                    Param配置
                    <el-button :circle="true" size="small" @click="(e) => addHttpNodeFormItem(e, 'params')"
                        class="addFormItem">
                        <el-icon :size="14">
                            <Plus />
                        </el-icon>
                    </el-button>
                </template>
                <div class="form__container">
                    <div v-for="(property, index) in httpNodeData.params" :key="index">
                        <el-row>
                            <el-form-item :label="index === 0 ? '参数名' : ''"
                                :prop="httpNodeData.params.length > index ? `params.${index}.name` : undefined" :rules="[
                                    { required: true, message: '请输入参数名123', trigger: 'blur' },
                                ]">
                                <el-input class="param-name" v-model="property.name" placeholder="请输入" clearable />
                            </el-form-item>
                            <el-form-item :label="index === 0 ? '参数值' : ''"
                                :prop="httpNodeData.params.length > index ? `params.${index}.input` : undefined">
                                <el-select v-model="property.type" class="param-type" @change="handleTypeChange(index)">
                                    <el-option label="引用" value="quote" />
                                    <el-option label="输入" value="input" />
                                </el-select>
                                <el-form-item v-if="property.type === 'input'" :rules="[
                                    {
                                        required: property?.required ?? true,
                                        message: '请输入参数值',
                                        trigger: 'blur',
                                    },
                                ]" :prop="httpNodeData.params.length > index ? `params.${index}.input` : undefined">
                                    <el-input-number class="param-value" v-if="property.componentType === 'number'"
                                        v-model="property.input" :min="0" :max="property.max || Infinity"
                                        :controls="false" :step-strictly="true" placeholder="请输入" clearable />
                                    <el-select v-model="property.input" class="param-value"
                                        v-else-if="property.componentType === 'select'">
                                        <el-option v-for="item in property.selectOptions" :key="item.value"
                                            :label="item.label" :value="item.value" />
                                    </el-select>
                                    <el-input class="param-value" v-else v-model="property.input" placeholder="请输入"
                                        clearable />
                                </el-form-item>
                                <el-form-item v-if="property.type === 'quote'" :rules="[
                                    {
                                        required: true,
                                        message: '请选择参数值',
                                        trigger: 'blur',
                                    },
                                ]" :prop="`params.${index}.quote`">
                                    <el-cascader :ref="(el) => {
                                            if (el) cascaderRefs[index] = el;
                                        }
                                        " v-model="property.quote" :checkStrictly="true" :options="quoteOptions" placeholder="请选择"
                                        @visible-change="
                                            (visible) => visibleChange(visible, index, property.quote)
                                        " @change="(value) => cascaderChange(value, index, httpNodeData, 'params')" />
                                </el-form-item>
                            </el-form-item>
                            <el-button :icon="Minus" circle size="small" @click="handleHttpNodeDelete('params', index)"
                                class="deleteBtn" />
                        </el-row>
                    </div>
                </div>
            </el-collapse-item>
            <el-collapse-item name="4" title="Body配置" icon-position="left">
                <template #title>
                Body配置
                <el-button
                    :circle="true"
                    size="small"
                    @click="(e) => addHttpNodeFormItem(e, 'body')"
                    class="addFormItem"
                    v-if="httpNodeData?.body?.type === 'form-data'"
                >
                    <el-icon :size="14"><Plus /></el-icon>
                </el-button>
                </template>
                <div class="form__container">
                <el-select v-model="httpNodeData.body.type">
                    <el-option label="JSON" value="json" />
                    <el-option label="form-data" value="form-data" />
                </el-select>
                <div class="code__container" v-show="httpNodeData?.body?.type === 'json'">
                    <div ref="codeRef" style="width: 100%; height: 100%"></div>
                </div>
                <div class="test" v-if="httpNodeData?.body?.type === 'form-data'">
                    <div v-for="(property, index) in httpNodeData.body.formData" :key="index">
                    <el-row>
                        <el-form-item
                        :label="index === 0 ? '参数名' : ''"
                        :prop="`body.formData.${index}.name`"
                        :rules="[
                            { required: true, message: '请输入参数名', trigger: 'blur' },
                        ]"
                        >
                        <el-input
                            class="param-name"
                            v-model="property.name"
                            placeholder="请输入"
                            clearable
                        />
                        </el-form-item>
                        <el-form-item
                        :label="index === 0 ? '参数值' : ''"
                        :prop="`body.formData.${index}.input`"
                        >
                        <el-select
                            v-model="property.type"
                            class="param-type"
                            @change="handleTypeChange(index, 'httpBody')"
                        >
                            <el-option label="引用" value="quote" />
                            <el-option label="输入" value="input" />
                        </el-select>
                        <el-form-item
                            v-if="property.type === 'input'"
                            :rules="[
                            {
                                required: property?.required ?? true,
                                message: '请输入参数值',
                                trigger: 'blur',
                            },
                            ]"
                            :prop="`body.formData.${index}.input`"
                        >
                            <el-input-number
                            class="param-value"
                            v-if="property.componentType === 'number'"
                            v-model="property.input"
                            :min="0"
                            :max="property.max || Infinity"
                            :controls="false"
                            :step-strictly="true"
                            placeholder="请输入"
                            clearable
                            />
                            <el-select
                            v-model="property.input"
                            class="param-value"
                            v-else-if="property.componentType === 'select'"
                            >
                            <el-option
                                v-for="item in property.selectOptions"
                                :key="item.value"
                                :label="item.label"
                                :value="item.value"
                            />
                            </el-select>
                            <el-input
                            class="param-value"
                            v-else
                            v-model="property.input"
                            placeholder="请输入"
                            clearable
                            />
                        </el-form-item>
                        <el-form-item
                            v-if="property.type === 'quote'"
                            :rules="[
                            {
                                required: true,
                                message: '请选择参数值',
                                trigger: 'blur',
                            },
                            ]"
                            :prop="`body.formData.${index}.quote`"
                        >
                            <el-cascader
                            :ref="
                                (el) => {
                                if (el) cascaderRefs[index] = el;
                                }
                            "
                            v-model="property.quote"
                            :checkStrictly="true"
                            :options="quoteOptions"
                            placeholder="请选择"
                            @visible-change="
                                (visible) => visibleChange(visible, index, property.quote, 'httpBody')
                            "
                            @change="(value) => cascaderChange(value, index, httpNodeData, 'body')"
                            />
                        </el-form-item>
                        </el-form-item>
                        <el-button
                        :icon="Minus"
                        circle
                        size="small"
                        @click="handleHttpNodeDelete('body', index)"
                        class="deleteBtn"
                    />
                    </el-row>
                    </div>
                </div>
                </div>
          </el-collapse-item>
        </el-collapse>
    </el-form>
</template>

<script setup>
import { ref, reactive, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
import { Plus, Minus } from '@element-plus/icons-vue'
import FormItemRecursive from '../FormItemRecursive.vue'
import * as monaco from 'monaco-editor';
import { getInput, transformHttpNodeData } from '@/utils/flow'
import { useQuote } from './useQuote.js'

const props = defineProps({
    data: Object
})

const emit = defineEmits(['save-success', 'save-error'])

const formData = reactive({
    nodeParams: [],
    outputParams: []
})

const codeRef = ref()
let editorInstance

/**
 * 判断 hasErrors 对应的数据或交互；作用范围仅限当前组件或模块。
 */
function hasErrors() {
  const model = editorInstance.getModel();
  if (!model) return false;
  
  // 获取当前模型的所有标记
  const markers = monaco.editor.getModelMarkers({ resource: model.uri });
  // 检查是否存在错误级别标记
  return markers.some(marker => marker.severity === monaco.MarkerSeverity.Error);
}

/**
 * 初始化 initEditor 对应的数据或交互；作用范围仅限当前组件或模块。
 * @param {*} type 目标类型
 */
const initEditor = (type) => {
  monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
    target: monaco.languages.typescript.ScriptTarget.ES2020,
    allowNonTsExtensions: true,          // 允许非 ts 扩展名（.js）
    checkJs: true,                       // 对 .js 文件进行类型检查
    strict: true,                        // 启用所有严格检查
    noImplicitAny: false,                  // 禁止隐式 any
    noUnusedLocals: true,                 // 未使用的局部变量报错（可选）
    noUnusedParameters: true,              // 未使用的参数报错（可选）
  });

  // 确保语义验证开启（默认就是开启的，但可以显式设置）
  monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
      noSemanticValidation: false,          // 开启语义检查
      noSyntaxValidation: false,             // 开启语法检查
  });

  editorInstance = monaco.editor.create(codeRef.value, {
    value: ['{}'].join('\n'),
    language: 'json',
    fontSize: 14,
    lineNumbers: 'on',
    roundedSelection: true,
    scrollBeyondLastLine: false,
    formatOnPaste: true,
    formatOnType: true,
    quickSuggestions: true,
        suggestOnTriggerCharacters: true,
        // 自动完成
        suggest: {
            showWords: true,
            showFunctions: true,
            showVariables: true,
            showClasses: true,
            showModules: true,
        },
  });
}

// 设置代码值
/**
 * 设置 setValue 对应的数据或交互；作用范围仅限当前组件或模块。
 * @param {*} value 待处理的新值
 */
const setValue = (value) => {
  if (editorInstance) {
    editorInstance.setValue(value)
  }
}

// 销毁编辑器
/**
 * 销毁 disposeEditor 对应的数据或交互；作用范围仅限当前组件或模块。
 */
const disposeEditor = () => {
  if (editorInstance) {
    editorInstance.dispose()
    editorInstance = null
  }
}

const rules = reactive({})
const dynamicFormRef = ref()
const activeNames = ref(['1', '2', '3', '4'])

// 使用共享的 quote 逻辑
const { quoteOptions, cascaderRefs, handleTypeChange, cascaderChange, visibleChange } = useQuote(props.data.id)

// 添加表单项
/**
 * 新增 addFormItem 对应的数据或交互；作用范围仅限当前组件或模块。
 * @param {*} e 触发操作的浏览器事件
 * @param {*} type 目标类型
 */
const addFormItem = (e, type) => {
    e.stopPropagation()
    const obj = {
        name: '',
        type: type === 'nodeParams' ? 'input' : 'string',
        required: false,
        children: [],
        input: ''
    }
    if (!formData[type]) formData[type] = []
    formData[type].push(obj)
}

// 删除输入参数（非递归）
/**
 * 处理 handleDelete 对应的数据或交互；作用范围仅限当前组件或模块。
 * @param {*} index 目标项索引
 */
const handleDelete = (index) => {
    formData.nodeParams.splice(index, 1)
}

// 删除顶层输出参数（递归删除通过 FormItemRecursive 的 emit 处理）
/**
 * 删除 deleteTopLevelItem 对应的数据或交互；作用范围仅限当前组件或模块。
 * @param {*} fullPath 字段完整路径
 * @param {*} propPath 字段校验路径
 */
const deleteTopLevelItem = (fullPath, propPath) => {
    let currentLevel = formData[propPath]
    for (let i = 0; i < fullPath.length - 1; i++) {
        currentLevel = currentLevel[fullPath[i]].children
    }
    const lastIndex = fullPath[fullPath.length - 1]
    currentLevel.splice(lastIndex, 1)
}

// HTTP 节点数据
const httpNodeData = ref({
    body: {
        bodyType: 'json',
        json: '{}',
        formData: []
    }
});

/**
 * 新增 addHttpNodeFormItem 对应的数据或交互；作用范围仅限当前组件或模块。
 * @param {*} e 触发操作的浏览器事件
 * @param {*} type 目标类型
 */
const addHttpNodeFormItem = (e, type) => {
  e.stopPropagation();
  if (type === 'body') {
    if (!httpNodeData.value.body.formData) {
      httpNodeData.value.body.formData = [];
    }
    httpNodeData.value.body.formData.push({ name: "", type: "input", input: ""});
  } else {
    if (!httpNodeData.value[type]) {
      httpNodeData.value[type] = [];
    }
    httpNodeData.value[type].push({ name: "", type: "input", input: ""});
  }
};

/**
 * 处理 handleHttpNodeDelete 对应的数据或交互；作用范围仅限当前组件或模块。
 * @param {*} type 目标类型
 * @param {*} index 目标项索引
 */
const handleHttpNodeDelete = (type, index) => {
  if (type === 'body') {
    httpNodeData.value.body.formData.splice(index, 1);
  } else {
    httpNodeData.value[type].splice(index, 1);
  }
};

// 初始化数据
/**
 * 初始化 initData 对应的数据或交互；作用范围仅限当前组件或模块。
 */
const initData = () => {
    const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || []))
    const transformedData = transformHttpNodeData(nodeParams);

    httpNodeData.value = transformedData;
    if (httpNodeData.value.body.type === 'json') {
        nextTick(() => {
        initEditor('http');
      });
        setTimeout(() => {
            if (editorInstance) {
                setValue(httpNodeData.value.body.json || '{}')
            }
        }, 200)
    }
}

// 保存验证
/**
 * 校验 validateAndSave 对应的数据或交互；作用范围仅限当前组件或模块。
 */
const validateAndSave = async () => {
    // 分区校验动态输入、请求头、查询参数和请求体；JSON 请求体还需通过编辑器语法检查。
    // 全部分区有效后才一次性写回节点属性，防止半成品配置覆盖画布中的可用数据。
    let inputValid = true
    if (dynamicFormRef.value) {
        await dynamicFormRef.value.validate((valid) => { if (!valid) inputValid = false })
    }


    const nodeParams = []
    nodeParams.push({ name: "config", type: "input", input: "", children: httpNodeData.value.config, disabled: true, required: true })
    if (httpNodeData.value?.headers?.length > 0) {
    nodeParams.push({ name: "headers", type: "input", input: "", children: httpNodeData.value.headers, disabled: true, required: true })
    }
    if (httpNodeData.value?.params?.length > 0) {
    nodeParams.push({ name: "params", type: "input", input: "", children: httpNodeData.value.params, disabled: true, required: true })
    }
    
    const bodyObj = { 
    name: "body", type: "input", input: "", children: [
        { name: 'bodyType', type: "input", input: httpNodeData.value.body.type, disabled: true },
        { name: 'json', type: "input", input: httpNodeData.value.body.type === 'json' ? editorInstance.getValue() : '' },
        { name: 'formData', type: "input", input: "", children: httpNodeData.value.body.formData }
    ]
    }
    nodeParams.push(bodyObj)

    // 保存到 lf
    lf.setProperties(props.data.id, {
        ...props.data.properties,
        nodeParams
    })

    if (httpNodeData.value.body.type === 'json') {
        if (hasErrors()) {
            emit('save-error')
            return
        }
    }

    if (inputValid) {
        emit('save-success')
    } else {
        emit('save-error')
    }
}


onMounted(() => {
  nextTick(() => {
    initData()
  })
})

defineExpose({ validateAndSave })

onBeforeUnmount(() => {
  disposeEditor()
})
</script>

<style lang="scss" scoped>
.http-form {
  width: 100%;

  .el-collapse {
    width: 100%;
  }
}

.form__container {
    margin: 12px 0;

    :deep(.el-row) {
        align-items: end;

        .el-form-item {
            margin-right: 12px;
        }

        .param-name {
            width: 160px;
        }

        .param-type {
            width: 80px;
        }

        .param-value {
            width: 160px;
        }

    }

    .sub-properties {
        margin-left: 10px;

        .zw {
            margin-left: 15px;

            &::before {
                content: "";
                position: absolute;
                left: 0;
                top: -4px;
                width: 10px;
                border-left: 1px solid gray;
                border-bottom: 1px solid gray;
                border-bottom-left-radius: 4px;
                background-color: transparent;
                height: 24px;
            }
        }
    }

    .gSon-properties {
        margin-left: 10px;

        .zw {
            margin-left: 15px;

            &::before {
                content: "";
                position: absolute;
                left: 0;
                top: -4px;
                width: 10px;
                border-left: 1px solid gray;
                border-bottom: 1px solid gray;
                border-bottom-left-radius: 4px;
                background-color: transparent;
                height: 24px;
            }
        }
    }

    .deleteBtn {
        margin-bottom: 22px;
        cursor: pointer;
    }
}

.code__container {
  display: flex;
  position: relative;
  text-align: initial;
  width: 100%;
  height: 300px;
  margin: 12px 0;
}
</style>
