import NodeTableComponent, {
  DataTemplateInterface,
} from "../NodeTableComponent/NodeTableComponent";
import { invoke } from "@tauri-apps/api/core";
import { Select, Space } from "antd";
import { useEffect, useMemo, useState } from "react";
// 写一个组件，用于展示位枚举值
interface BitEnumComponentProps {
  value: number;
  enum: {
    [key: number]: {
      enum_name: string; // 枚举值名称
      description?: string; // 枚举值描述
    };
  };
  onChange?: (value: any, options: any) => void;
}

const BitEnumComponent = (props: BitEnumComponentProps) => {
  const formatOptions = useMemo(() => {
    const options = Object.entries(props.enum).map(([key, value]) => {
      return {
        label: value.enum_name,
        value: key,
        title: value.description,
      };
    });
    return options;
  }, [props.enum, props.value]);

  const formatValue = useMemo(() => {
    const value = [];
    for (const key in props.enum) {
      if (props.value & parseInt(key)) {
        value.push(key);
      }
    }
    return value;
  }, [props.value]);

  const handleChange = (value: number[], options) => {
    // 如果props.onChange存在，那么调用
    props.onChange?.(value, options);
    // TODO: 做一些自己的事
  };

  return (
    <>
      <Space style={{ width: "100%" }} direction="vertical">
        <Select
          mode="multiple"
          allowClear
          style={{ width: "100%" }}
          options={formatOptions}
          value={formatValue}
          onChange={handleChange}
        />
      </Space>
    </>
  );
};

export default function FileHeader() {
  const [data, setData] = useState<any[]>([]);
  const [valueHex, setValueHex] = useState(false);

  const handleChangeBitEnum = (record: any, value: number[], _options) => {
    const { name } = record;
    const newData: any = { ...data };
    newData.fields[name] = value.reduce(
      (prev, cur: any) => prev | parseInt(cur),
      0
    );
    setData(newData);
  };

  const dataTemplate: DataTemplateInterface = {
    machine: {
      name: "machine",
      description: "目标机器类型，例如 x86 或 x64。",
      offset: 0,
      size: 2,
      value: null,
      data_type: "hex",
    },
    number_of_sections: {
      name: "number_of_sections",
      description: "节的数量，表示文件中包含的段数量。",
      offset: 2,
      size: 2,
      value: null,
      data_type: "hex",
    },
    time_date_stamp: {
      name: "time_date_stamp",
      description: "文件的创建时间戳，以自 1970-01-01 的秒数表示。",
      offset: 4,
      size: 4,
      value: null,
      data_type: "hex",
    },
    pointer_to_symbol_table: {
      name: "pointer_to_symbol_table",
      description: "符号表的文件偏移（通常为 0 表示未使用）。",
      offset: 8,
      size: 4,
      value: null,
      data_type: "hex",
    },
    number_of_symbols: {
      name: "number_of_symbols",
      description: "符号表中符号的数量（通常为 0 表示未使用）。",
      offset: 12,
      size: 4,
      value: null,
      data_type: "hex",
    },
    size_of_optional_header: {
      name: "size_of_optional_header",
      description: "可选头的大小，用于进一步描述文件。",
      offset: 16,
      size: 2,
      value: null,
      data_type: "hex",
    },
    characteristics: {
      name: "characteristics",
      description: "文件特性标志，例如可执行、DLL、移除调试信息等。",
      offset: 18,
      size: 2,
      value: null,
      data_type: "bit_enum",
      enum: {
        0x1: {
          enum_name: "RELOCS_STRIPPED",
          description: "已从文件中移除重定位信息。",
        },
        0x2: {
          enum_name: "EXECUTABLE_IMAGE",
          description: "文件是可执行的（例如，没有未解析的外部引用）。",
        },
        0x4: {
          enum_name: "LINE_NUMS_STRIPPED",
          description: "已从文件中移除行号信息。",
        },
        0x8: {
          enum_name: "LOCAL_SYMS_STRIPPED",
          description: "已从文件中移除本地符号信息。",
        },
        0x10: {
          enum_name: "AGGRESSIVE_WS_TRIM",
          description: "积极地减少工作集。",
        },
        0x20: {
          enum_name: "LARGE_ADDRESS_AWARE",
          description: "应用程序可以处理大于 2GB 的地址。",
        },
        0x80: {
          enum_name: "BYTES_REVERSED_LO",
          description: "机器字的字节顺序被颠倒（低位字节）。",
        },
        0x100: {
          enum_name: "MACHINE_32BIT",
          description: "32 位字长的机器。",
        },
        0x200: {
          enum_name: "DEBUG_STRIPPED",
          description: "调试信息已被移到 .DBG 文件中。",
        },
        0x400: {
          enum_name: "REMOVABLE_RUN_FROM_SWAP",
          description: "如果映像位于可移动介质上，则复制并从交换文件运行。",
        },
        0x800: {
          enum_name: "NET_RUN_FROM_SWAP",
          description: "如果映像位于网络上，则复制并从交换文件运行。",
        },
        0x1000: {
          enum_name: "SYSTEM",
          description: "系统文件。",
        },
        0x2000: {
          enum_name: "DLL",
          description: "文件是一个 DLL。",
        },
        0x4000: {
          enum_name: "UP_SYSTEM_ONLY",
          description: "文件只能在单处理器机器上运行。",
        },
        0x8000: {
          enum_name: "BYTES_REVERSED_HI",
          description: "机器字的字节顺序被颠倒（高位字节）。",
        },
      },
    },
  };
  const command = "command_get_pe_data_file_header";
  const columns = [
    {
      title: "字段名",
      dataIndex: "name",
      key: "name",
    },
    {
      title: "偏移",
      dataIndex: "offset",
      key: "offset",
      hexSwitch: true,
    },
    {
      title: "大小",
      dataIndex: "size",
      key: "size",
    },
    {
      title: "值",
      dataIndex: "value",
      key: "value",
      editable: true,
      render: (text: any, record: any) => {
        if (record.data_type === "bit_enum") {
          return (
            <BitEnumComponent
              value={text}
              enum={record.enum}
              onChange={(value, options) =>
                handleChangeBitEnum(record, value, options)
              }
            />
          );
        } else if (record.data_type === "hex") {
          return (
            <span style={{ cursor: "pointer" }}>
              {valueHex ? `0x${text.toString(16).toUpperCase()}` : text}
            </span>
          );
        }
        return <span>{text}</span>;
      },
      onHeaderCell: () => ({
        onClick: () => {
          setValueHex(!valueHex);
        },
      }),
    },
    {
      title: "描述信息",
      dataIndex: "description",
      key: "description",
      minWidth: 200,
    },
  ];

  useEffect(() => {
    invoke(command).then((res) => {
      setData(res as any);
    });
  }, []);

  return (
    <NodeTableComponent
      dataTemplate={dataTemplate}
      defaultData={data as any}
      columns={columns as any}
    ></NodeTableComponent>
  );
}
