<template>
  <div class="buffer-editor">
    <!-- 操作类型选择 -->
    <div class="operation-cards">
      <div
        v-for="op in operations"
        :key="op.name"
        :class="['operation-card', { active: argvs.operation === op.name }]"
        @click="updateArgvs('operation', op.name)"
        :data-value="op.name"
      >
        <q-icon
          :name="op.icon"
          size="16px"
          :color="argvs.operation === op.name ? 'primary' : 'grey'"
        />
        <div class="text-caption">{{ op.label }}</div>
      </div>
    </div>

    <!-- 操作配置 -->
    <div class="operation-options q-mt-sm">
      <div class="options-container">
        <!-- 创建 Buffer -->
        <div v-if="argvs.operation === 'from'" class="row q-col-gutter-sm">
          <VariableInput
            :model-value="argvs.data"
            @update:model-value="(val) => updateArgvs('data', val)"
            label="数据"
            icon="text_fields"
            class="col"
          />
          <q-select
            :model-value="argvs.encoding"
            @update:model-value="(val) => updateArgvs('encoding', val)"
            :options="encodings"
            label="编码"
            dense
            filled
            emit-value
            map-options
            options-dense
            class="col-3"
          />
        </div>

        <!-- 转换为字符串 -->
        <div
          v-if="argvs.operation === 'toString'"
          class="column q-col-gutter-sm"
        >
          <VariableInput
            :model-value="argvs.buffer"
            @update:model-value="(val) => updateArgvs('buffer', val)"
            label="Buffer"
            icon="memory"
          />
          <div class="row q-col-gutter-sm">
            <div class="col-12 col-sm-4">
              <q-select
                :model-value="argvs.encoding"
                @update:model-value="(val) => updateArgvs('encoding', val)"
                :options="encodings"
                label="编码"
                dense
                filled
                emit-value
                map-options
                options-dense
              />
            </div>
            <div class="col-12 col-sm-4">
              <NumberInput
                :model-value="argvs.start"
                @update:model-value="(val) => updateArgvs('start', val)"
                label="起始位置"
              />
            </div>
            <div class="col-12 col-sm-4">
              <NumberInput
                :model-value="argvs.end"
                @update:model-value="(val) => updateArgvs('end', val)"
                label="结束位置"
              />
            </div>
          </div>
        </div>

        <!-- 写入数据 -->
        <div v-if="argvs.operation === 'write'" class="column q-col-gutter-sm">
          <div class="row q-col-gutter-sm">
            <VariableInput
              :model-value="argvs.buffer"
              @update:model-value="(val) => updateArgvs('buffer', val)"
              label="Buffer"
              icon="memory"
              class="col"
            />
            <VariableInput
              :model-value="argvs.string"
              @update:model-value="(val) => updateArgvs('string', val)"
              label="要写入的字符串"
              icon="edit"
              class="col"
            />
          </div>
          <div class="row q-col-gutter-sm">
            <div class="col-4">
              <NumberInput
                :model-value="argvs.offset"
                @update:model-value="(val) => updateArgvs('offset', val)"
                label="偏移量"
              />
            </div>
            <div class="col-4">
              <NumberInput
                :model-value="argvs.length"
                @update:model-value="(val) => updateArgvs('length', val)"
                label="长度"
              />
            </div>
            <div class="col-4">
              <q-select
                :model-value="argvs.encoding"
                @update:model-value="(val) => updateArgvs('encoding', val)"
                :options="encodings"
                label="编码"
                dense
                filled
                emit-value
                map-options
                options-dense
              />
            </div>
          </div>
        </div>

        <!-- 填充数据 -->
        <div v-if="argvs.operation === 'fill'" class="column q-col-gutter-sm">
          <div class="row q-col-gutter-sm">
            <VariableInput
              :model-value="argvs.buffer"
              @update:model-value="(val) => updateArgvs('buffer', val)"
              label="Buffer"
              icon="memory"
              class="col"
            />
            <VariableInput
              :model-value="argvs.value"
              @update:model-value="(val) => updateArgvs('value', val)"
              label="填充值"
              icon="format_color_fill"
              class="col"
            />
          </div>
          <div class="row q-col-gutter-sm">
            <div class="col-4">
              <NumberInput
                :model-value="argvs.offset"
                @update:model-value="(val) => updateArgvs('offset', val)"
                label="起始位置"
              />
            </div>
            <div class="col-12 col-sm-4">
              <NumberInput
                :model-value="argvs.end"
                @update:model-value="(val) => updateArgvs('end', val)"
                label="结束位置"
              />
            </div>
            <div class="col-12 col-sm-4">
              <q-select
                :model-value="argvs.encoding"
                @update:model-value="(val) => updateArgvs('encoding', val)"
                :options="encodings"
                label="编码"
                dense
                filled
                emit-value
                map-options
                options-dense
              />
            </div>
          </div>
        </div>

        <!-- 复制数据 -->
        <div v-if="argvs.operation === 'copy'" class="column q-col-gutter-sm">
          <div class="row q-col-gutter-sm">
            <VariableInput
              :model-value="argvs.source"
              @update:model-value="(val) => updateArgvs('source', val)"
              label="源Buffer"
              icon="content_copy"
              class="col"
            />
            <VariableInput
              :model-value="argvs.target"
              @update:model-value="(val) => updateArgvs('target', val)"
              label="目标Buffer"
              icon="save"
              class="col"
            />
          </div>
          <div class="row q-col-gutter-sm">
            <div class="col-4">
              <NumberInput
                :model-value="argvs.targetStart"
                @update:model-value="(val) => updateArgvs('targetStart', val)"
                label="目标起始位置"
              />
            </div>
            <div class="col-12 col-sm-4">
              <NumberInput
                :model-value="argvs.sourceStart"
                @update:model-value="(val) => updateArgvs('sourceStart', val)"
                label="源起始位置"
              />
            </div>
            <div class="col-12 col-sm-4">
              <NumberInput
                :model-value="argvs.sourceEnd"
                @update:model-value="(val) => updateArgvs('sourceEnd', val)"
                label="源结束位置"
              />
            </div>
          </div>
        </div>

        <!-- 比较数据 -->
        <div
          v-if="argvs.operation === 'compare'"
          class="column q-col-gutter-sm"
        >
          <div class="row q-col-gutter-sm">
            <VariableInput
              :model-value="argvs.buf1"
              @update:model-value="(val) => updateArgvs('buf1', val)"
              label="Buffer 1"
              icon="memory"
              class="col"
            />
            <VariableInput
              :model-value="argvs.buf2"
              @update:model-value="(val) => updateArgvs('buf2', val)"
              label="Buffer 2"
              icon="memory"
              class="col"
            />
          </div>
        </div>

        <!-- 连接 Buffer -->
        <div v-if="argvs.operation === 'concat'" class="column q-gutter-sm">
          <ArrayEditor
            :model-value="argvs.buffers"
            @update:model-value="(val) => updateArgvs('buffers', val)"
            label="Buffer"
            icon="memory"
          />
          <NumberInput
            :model-value="argvs.totalLength"
            @update:model-value="(val) => updateArgvs('totalLength', val)"
            label="总长度（可选）"
          />
        </div>

        <!-- 查找数据 -->
        <div
          v-if="argvs.operation === 'indexOf'"
          class="column q-col-gutter-sm"
        >
          <div class="row q-col-gutter-sm">
            <VariableInput
              :model-value="argvs.buffer"
              @update:model-value="(val) => updateArgvs('buffer', val)"
              label="Buffer"
              icon="memory"
              class="col"
            />
            <VariableInput
              :model-value="argvs.value"
              @update:model-value="(val) => updateArgvs('value', val)"
              label="要查找的值"
              icon="search"
              class="col"
            />
          </div>
          <div class="row q-col-gutter-sm">
            <div class="col-12 col-sm-6">
              <NumberInput
                :model-value="argvs.byteOffset"
                @update:model-value="(val) => updateArgvs('byteOffset', val)"
                label="起始位置"
              />
            </div>
            <div class="col-12 col-sm-6">
              <q-select
                :model-value="argvs.encoding"
                @update:model-value="(val) => updateArgvs('encoding', val)"
                :options="encodings"
                label="编码"
                dense
                filled
                emit-value
                map-options
                options-dense
              />
            </div>
          </div>
        </div>

        <!-- 切片数据 -->
        <div v-if="argvs.operation === 'slice'" class="row q-col-gutter-sm">
          <VariableInput
            :model-value="argvs.buffer"
            @update:model-value="(val) => updateArgvs('buffer', val)"
            label="Buffer"
            icon="memory"
            class="col"
          />
          <NumberInput
            :model-value="argvs.start"
            @update:model-value="(val) => updateArgvs('start', val)"
            label="起始位置"
            class="col"
          />
          <NumberInput
            :model-value="argvs.end"
            @update:model-value="(val) => updateArgvs('end', val)"
            label="结束位置"
            class="col"
          />
        </div>

        <!-- 交换字节序 -->
        <div v-if="argvs.operation === 'swap'" class="row q-col-gutter-sm">
          <VariableInput
            :model-value="argvs.buffer"
            @update:model-value="(val) => updateArgvs('buffer', val)"
            label="Buffer"
            class="col"
            icon="memory"
          />
          <q-select
            :model-value="argvs.size"
            @update:model-value="(val) => updateArgvs('size', val)"
            :options="swapSizes"
            label="字节大小"
            class="col-3"
            dense
            filled
            emit-value
            map-options
            options-dense
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { defineComponent } from "vue";
import { stringifyArgv, parseFunction } from "js/composer/formatString";
import VariableInput from "components/composer/ui/VariableInput.vue";
import NumberInput from "components/composer/ui/NumberInput.vue";
import ArrayEditor from "components/composer/ui/ArrayEditor.vue";

export default defineComponent({
  name: "BufferEditor",
  components: {
    VariableInput,
    NumberInput,
    ArrayEditor,
  },
  props: {
    modelValue: {
      type: Object,
      required: true,
    },
  },
  emits: ["update:modelValue"],
  data() {
    return {
      operations: [
        { name: "from", label: "创建Buffer", icon: "add_box" },
        { name: "toString", label: "转换字符串", icon: "text_fields" },
        { name: "write", label: "写入数据", icon: "edit" },
        { name: "fill", label: "填充数据", icon: "format_color_fill" },
        { name: "copy", label: "复制数据", icon: "content_copy" },
        { name: "compare", label: "比较数据", icon: "compare" },
        { name: "concat", label: "连接Buffer", icon: "merge" },
        { name: "indexOf", label: "查找数据", icon: "search" },
        { name: "slice", label: "切片数据", icon: "content_cut" },
        { name: "swap", label: "交换字节序", icon: "swap_horiz" },
      ],
      encodings: [
        { label: "UTF-8", value: "utf8" },
        { label: "UTF-16LE", value: "utf16le" },
        { label: "Latin1", value: "latin1" },
        { label: "Base64", value: "base64" },
        { label: "Hex", value: "hex" },
        { label: "ASCII", value: "ascii" },
        { label: "Binary", value: "binary" },
        { label: "UCS-2", value: "ucs2" },
      ],
      swapSizes: [
        { label: "16位", value: 16 },
        { label: "32位", value: 32 },
        { label: "64位", value: 64 },
      ],
      defaultArgvs: {
        operation: "from",
        data: {
          value: "",
          isString: true,
          __varInputVal__: true,
        },
        buffer: {
          value: "",
          isString: false,
          __varInputVal__: true,
        },
        encoding: "utf8",
        start: 0,
        end: 0,
        string: {
          value: "",
          isString: true,
          __varInputVal__: true,
        },
        offset: 0,
        length: 0,
        value: {
          value: "",
          isString: true,
          __varInputVal__: true,
        },
        source: {
          value: "",
          isString: false,
          __varInputVal__: true,
        },
        target: {
          value: "",
          isString: false,
          __varInputVal__: true,
        },
        targetStart: 0,
        sourceStart: 0,
        sourceEnd: 0,
        buf1: {
          value: "",
          isString: false,
          __varInputVal__: true,
        },
        buf2: {
          value: "",
          isString: false,
          __varInputVal__: true,
        },
        buffers: [
          {
            value: "",
            isString: false,
            __varInputVal__: true,
          },
        ],
        totalLength: undefined,
        byteOffset: 0,
        size: 16,
      },
    };
  },
  computed: {
    argvs: {
      get() {
        return (
          this.modelValue.argvs ||
          this.parseCodeToArgvs(this.modelValue.code) || {
            ...this.defaultArgvs,
          }
        );
      },
      set(value) {
        this.updateModelValue(value);
      },
    },
  },
  methods: {
    generateCode(argvs = this.argvs) {
      switch (argvs.operation) {
        case "from":
          return `${this.modelValue.value}.${argvs.operation}(${stringifyArgv(
            argvs.data
          )}, "${argvs.encoding}")`;

        case "toString":
          return `${this.modelValue.value}.${argvs.operation}(${stringifyArgv(
            argvs.buffer
          )}, "${argvs.encoding}", ${argvs.start}, ${argvs.end})`;

        case "write":
          return `${this.modelValue.value}.${argvs.operation}(${stringifyArgv(
            argvs.buffer
          )}, ${stringifyArgv(argvs.string)}, ${argvs.offset}, ${
            argvs.length
          }, "${argvs.encoding}")`;

        case "fill":
          return `${this.modelValue.value}.${argvs.operation}(${stringifyArgv(
            argvs.buffer
          )}, ${stringifyArgv(argvs.value)}, ${argvs.offset}, ${argvs.end}, "${
            argvs.encoding
          }")`;

        case "copy":
          return `${this.modelValue.value}.${argvs.operation}(${stringifyArgv(
            argvs.source
          )}, ${stringifyArgv(argvs.target)}, ${argvs.targetStart}, ${
            argvs.sourceStart
          }, ${argvs.sourceEnd})`;

        case "compare":
          return `${this.modelValue.value}.${argvs.operation}(${stringifyArgv(
            argvs.buf1
          )}, ${stringifyArgv(argvs.buf2)})`;

        case "concat":
          const buffersStr = argvs.buffers
            .map((buf) => stringifyArgv(buf))
            .join(", ");
          return `${this.modelValue.value}.${argvs.operation}([${buffersStr}]${
            argvs.totalLength !== undefined ? `, ${argvs.totalLength}` : ""
          })`;

        case "indexOf":
          return `${this.modelValue.value}.${argvs.operation}(${stringifyArgv(
            argvs.buffer
          )}, ${stringifyArgv(argvs.value)}, ${argvs.byteOffset}, "${
            argvs.encoding
          }")`;

        case "slice":
          return `${this.modelValue.value}.${argvs.operation}(${stringifyArgv(
            argvs.buffer
          )}, ${argvs.start}, ${argvs.end})`;

        case "swap":
          return `${this.modelValue.value}.${argvs.operation}(${stringifyArgv(
            argvs.buffer
          )}, ${argvs.size})`;

        default:
          return `${this.modelValue.value}.${argvs.operation}()`;
      }
    },
    parseCodeToArgvs(code) {
      if (!code) return null;

      try {
        // 定义需要使用variable格式的路径
        const variableFormatPaths = ["arg0", "arg0[*]"];

        const subFunc = code.match(/buffer\.(\w+)\((.*)\)/);

        switch (subFunc[1]) {
          case "write":
          case "fill":
          case "copy":
          case "compare":
          case "indexOf":
            variableFormatPaths.push("arg1");
            break;
        }

        // 使用 parseFunction 解析代码
        const result = parseFunction(code, { variableFormatPaths });
        if (!result) return this.defaultArgvs;

        const operation = result.name.split(".").pop();
        const args = result.args;

        const newArgvs = {
          ...this.defaultArgvs,
          operation,
        };

        switch (operation) {
          case "from":
            newArgvs.data = args[0];
            newArgvs.encoding = args[1]?.value || "utf8";
            break;

          case "toString":
            newArgvs.buffer = args[0];
            newArgvs.encoding = args[1]?.value || "utf8";
            newArgvs.start = args[2] ?? 0;
            newArgvs.end = args[3] ?? 0;
            break;

          case "write":
            newArgvs.buffer = args[0];
            newArgvs.string = args[1];
            newArgvs.offset = args[2] ?? 0;
            newArgvs.length = args[3] ?? 0;
            newArgvs.encoding = args[4]?.value || "utf8";
            break;

          case "fill":
            newArgvs.buffer = args[0];
            newArgvs.value = args[1];
            newArgvs.offset = args[2] ?? 0;
            newArgvs.end = args[3] ?? 0;
            newArgvs.encoding = args[4]?.value || "utf8";
            break;

          case "copy":
            newArgvs.source = args[0];
            newArgvs.target = args[1];
            newArgvs.targetStart = args[2] ?? 0;
            newArgvs.sourceStart = args[3] ?? 0;
            newArgvs.sourceEnd = args[4] ?? 0;
            break;

          case "compare":
            newArgvs.buf1 = args[0];
            newArgvs.buf2 = args[1];
            break;

          case "concat":
            if (Array.isArray(args[0])) {
              newArgvs.buffers = args[0];
            }
            newArgvs.totalLength = args[1];
            break;

          case "indexOf":
            newArgvs.buffer = args[0];
            newArgvs.value = args[1];
            newArgvs.byteOffset = args[2] ?? 0;
            newArgvs.encoding = args[3]?.value || "utf8";
            break;

          case "slice":
            newArgvs.buffer = args[0];
            newArgvs.start = args[1] ?? 0;
            newArgvs.end = args[2] ?? 0;
            break;

          case "swap":
            newArgvs.buffer = args[0];
            newArgvs.size = args[1] ?? 16;
            break;
        }

        return newArgvs;
      } catch (e) {
        console.error("解析Buffer参数失败:", e);
        return this.defaultArgvs;
      }
    },
    updateArgvs(key, value) {
      this.argvs = {
        ...this.argvs,
        [key]: value,
      };
    },
    getSummary(argvs) {
      const op = this.operations.find(
        (op) => op.name === argvs.operation
      )?.label;
      return op;
    },
    updateModelValue(argvs) {
      this.$emit("update:modelValue", {
        ...this.modelValue,
        summary: this.getSummary(argvs),
        argvs,
        code: this.generateCode(argvs),
      });
    },
  },
  mounted() {
    if (!this.modelValue.argvs && !this.modelValue.code) {
      this.updateModelValue(this.defaultArgvs);
    }
  },
  watch: {
    "argvs.operation": {
      immediate: true,
      handler(newVal) {
        this.$nextTick(() => {
          document
            .querySelector(`.operation-card[data-value="${newVal}"]`)
            ?.scrollIntoView({
              behavior: "smooth",
              block: "nearest",
              inline: "nearest",
            });
        });
      },
    },
  },
});
</script>

<style scoped>
.buffer-editor {
  display: flex;
  flex-direction: column;
}

.options-container {
  min-height: 32px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
</style>
