<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router";

import { api } from "@/api/client";
import { useUiStore } from "@/stores/ui";
import type {
  AdminBoardUpsertRequest,
  BoardConfig,
  BootConfig,
  DtbFileResponse,
  PowerManagementConfig,
  SerialPortSummary,
} from "@/types/api";

type PowerManagementKind = "custom" | "zhongsheng_relay";
type BootKind = "uboot" | "pxe";

interface BoardEditorFormState {
  id: string;
  board_type: string;
  tags_text: string;
  notes: string;
  disabled: boolean;
  serial_enabled: boolean;
  serial_port: string;
  serial_baud_rate: number;
  power_management_kind: PowerManagementKind;
  power_on_cmd: string;
  power_off_cmd: string;
  relay_serial_port: string;
  boot_kind: BootKind;
  use_tftp: boolean;
  dtb_name: string;
  pxe_notes: string;
}

const DEFAULT_SERIAL_BAUD_RATE = 115_200;

const route = useRoute();
const router = useRouter();
const ui = useUiStore();

const loading = ref(true);
const saving = ref(false);
const deleting = ref(false);
const refreshingSerials = ref(false);
const uploadingDtb = ref(false);
const validationError = ref("");
const form = ref<BoardEditorFormState>(defaultFormState());
const serialPorts = ref<SerialPortSummary[]>([]);
const dtbs = ref<DtbFileResponse[]>([]);
const dtbUploadName = ref("");
const dtbUploadFile = ref<File | null>(null);
const dtbFileInput = ref<HTMLInputElement | null>(null);
const showingDtbUploadModal = ref(false);
const isEditing = computed(() => typeof route.params.boardId === "string");
const boardId = computed(() => route.params.boardId as string | undefined);

function defaultFormState(): BoardEditorFormState {
  return {
    id: "",
    board_type: "",
    tags_text: "",
    notes: "",
    disabled: false,
    serial_enabled: false,
    serial_port: "",
    serial_baud_rate: DEFAULT_SERIAL_BAUD_RATE,
    power_management_kind: "custom",
    power_on_cmd: "",
    power_off_cmd: "",
    relay_serial_port: "",
    boot_kind: "uboot",
    use_tftp: false,
    dtb_name: "",
    pxe_notes: "",
  };
}

function boardToFormState(board: BoardConfig): BoardEditorFormState {
  const next = defaultFormState();
  next.id = board.id;
  next.board_type = board.board_type;
  next.tags_text = board.tags.join(", ");
  next.notes = board.notes ?? "";
  next.disabled = board.disabled;

  if (board.serial) {
    next.serial_enabled = true;
    next.serial_port = board.serial.port;
    next.serial_baud_rate = board.serial.baud_rate;
  }

  if (board.power_management.kind === "custom") {
    next.power_management_kind = "custom";
    next.power_on_cmd = board.power_management.power_on_cmd;
    next.power_off_cmd = board.power_management.power_off_cmd;
  } else {
    next.power_management_kind = "zhongsheng_relay";
    next.relay_serial_port = board.power_management.serial_port;
  }

  if (board.boot.kind === "uboot") {
    next.boot_kind = "uboot";
    next.use_tftp = board.boot.use_tftp;
    next.dtb_name = board.boot.dtb_name ?? "";
  } else {
    next.boot_kind = "pxe";
    next.pxe_notes = board.boot.notes ?? "";
  }

  return next;
}

function trimToNull(value: string): string | null {
  const trimmed = value.trim();
  return trimmed ? trimmed : null;
}

function splitTags(tagsText: string): string[] {
  return tagsText
    .split(/[,\n]/)
    .map((tag) => tag.trim())
    .filter((tag) => tag.length > 0);
}

function buildBootConfig(): BootConfig {
  if (form.value.boot_kind === "uboot") {
    return {
      kind: "uboot",
      use_tftp: form.value.use_tftp,
      dtb_name: trimToNull(form.value.dtb_name),
    };
  }

  return {
    kind: "pxe",
    notes: trimToNull(form.value.pxe_notes),
  };
}

function buildPowerManagementConfig(): PowerManagementConfig {
  if (form.value.power_management_kind === "custom") {
    return {
      kind: "custom",
      power_on_cmd: form.value.power_on_cmd.trim(),
      power_off_cmd: form.value.power_off_cmd.trim(),
    };
  }

  return {
    kind: "zhongsheng_relay",
    serial_port: form.value.relay_serial_port.trim(),
  };
}

function buildRequestPayload(): AdminBoardUpsertRequest {
  return {
    id: trimToNull(form.value.id),
    board_type: form.value.board_type.trim(),
    tags: splitTags(form.value.tags_text),
    notes: trimToNull(form.value.notes),
    disabled: form.value.disabled,
    serial: form.value.serial_enabled
      ? {
          port: form.value.serial_port.trim(),
          baud_rate: form.value.serial_baud_rate,
        }
      : null,
    power_management: buildPowerManagementConfig(),
    boot: buildBootConfig(),
  };
}

function validateForm(): string {
  const errors: string[] = [];

  if (!form.value.board_type.trim()) {
    errors.push("board_type 不能为空");
  }
  if (form.value.id.includes("/") || form.value.id.includes("\\")) {
    errors.push("板子 ID 不能包含路径分隔符");
  }
  if (form.value.serial_enabled && !form.value.serial_port.trim()) {
    errors.push("启用串口时必须选择串口设备");
  }
  if (form.value.serial_enabled && (!Number.isFinite(form.value.serial_baud_rate) || form.value.serial_baud_rate <= 0)) {
    errors.push("启用串口时波特率必须大于 0");
  }
  if (form.value.power_management_kind === "custom") {
    if (!form.value.power_on_cmd.trim()) {
      errors.push("Custom 电源管理必须填写开机命令");
    }
    if (!form.value.power_off_cmd.trim()) {
      errors.push("Custom 电源管理必须填写关机命令");
    }
  }
  if (form.value.power_management_kind === "zhongsheng_relay" && !form.value.relay_serial_port.trim()) {
    errors.push("中盛继电模块必须选择串口设备");
  }
  return errors.join("\n");
}

function serialOptions(currentValue: string) {
  const options = new Map<string, string>();
  for (const port of serialPorts.value) {
    options.set(port.port_name, port.label);
  }
  const trimmed = currentValue.trim();
  if (trimmed && !options.has(trimmed)) {
    options.set(trimmed, `${trimmed} (当前配置，未检测到)`);
  }
  return Array.from(options.entries()).map(([value, label]) => ({ value, label }));
}

function dtbOptions(currentValue: string) {
  const options = new Map<string, string>();
  for (const dtb of dtbs.value) {
    options.set(dtb.name, `${dtb.name} (${dtb.relative_tftp_path_template})`);
  }
  const trimmed = currentValue.trim();
  if (trimmed && !options.has(trimmed)) {
    options.set(trimmed, `${trimmed} (当前配置，未检测到)`);
  }
  return Array.from(options.entries()).map(([value, label]) => ({ value, label }));
}

async function loadSerialPorts() {
  serialPorts.value = await api.listSerialPorts();
}

async function refreshSerialPorts() {
  refreshingSerials.value = true;
  try {
    await loadSerialPorts();
    ui.setSuccess("已刷新串口列表");
  } catch (error) {
    ui.setError((error as Error).message);
  } finally {
    refreshingSerials.value = false;
  }
}

async function loadEditor() {
  loading.value = true;
  validationError.value = "";
  ui.clearMessages();

  try {
    const [ports, dtbList, board] = await Promise.all([
      api.listSerialPorts(),
      api.listDtbs(),
      isEditing.value && boardId.value ? api.getBoard(boardId.value) : Promise.resolve(null),
    ]);
    serialPorts.value = ports;
    dtbs.value = dtbList;
    form.value = board ? boardToFormState(board) : defaultFormState();
  } catch (error) {
    ui.setError((error as Error).message);
  } finally {
    loading.value = false;
  }
}

function onDtbFileChange(event: Event) {
  const input = event.target as HTMLInputElement;
  const file = input.files?.[0] ?? null;
  dtbUploadFile.value = file;
  if (file) {
    dtbUploadName.value = file.name;
  }
}

function openDtbUploadModal() {
  showingDtbUploadModal.value = true;
}

function closeDtbUploadModal() {
  showingDtbUploadModal.value = false;
  dtbUploadName.value = "";
  dtbUploadFile.value = null;
  if (dtbFileInput.value) {
    dtbFileInput.value.value = "";
  }
}

async function uploadDtbAndSelect() {
  if (!dtbUploadFile.value) {
    ui.setError("请选择要上传的 DTB 文件");
    return;
  }
  const dtbName = dtbUploadName.value.trim() || dtbUploadFile.value.name;
  if (!dtbName) {
    ui.setError("请填写 DTB 文件名");
    return;
  }

  uploadingDtb.value = true;
  try {
    const created = await api.createDtb(dtbName, dtbUploadFile.value);
    dtbs.value = [...dtbs.value.filter((item) => item.name !== created.name), created].sort((a, b) =>
      a.name.localeCompare(b.name),
    );
    form.value.dtb_name = created.name;
    closeDtbUploadModal();
    ui.setSuccess(`已上传 DTB ${created.name}`);
  } catch (error) {
    ui.setError((error as Error).message);
  } finally {
    uploadingDtb.value = false;
  }
}

async function saveBoard() {
  validationError.value = validateForm();
  if (validationError.value) {
    return;
  }

  saving.value = true;
  try {
    const payload = buildRequestPayload();
    const saved = isEditing.value && boardId.value
      ? await api.updateBoard(boardId.value, payload)
      : await api.createBoard(payload);
    form.value = boardToFormState(saved);
    ui.setSuccess(`已保存开发板 ${saved.id}`);
    await router.push(`/boards/${saved.id}`);
  } catch (error) {
    ui.setError((error as Error).message);
  } finally {
    saving.value = false;
  }
}

async function removeBoard() {
  if (!boardId.value) {
    return;
  }
  if (!window.confirm(`确认删除开发板 ${boardId.value} 吗？`)) {
    return;
  }

  deleting.value = true;
  try {
    await api.deleteBoard(boardId.value);
    ui.setSuccess(`已删除开发板 ${boardId.value}`);
    await router.push("/boards");
  } catch (error) {
    ui.setError((error as Error).message);
  } finally {
    deleting.value = false;
  }
}

onMounted(() => {
  void loadEditor();
});
</script>

<template>
  <section class="page-grid">
    <div class="panel">
      <div class="panel-heading">
        <div>
          <p class="eyebrow">{{ isEditing ? "编辑现有开发板" : "创建新开发板" }}</p>
          <h3>{{ isEditing ? "开发板配置" : "新建开发板" }}</h3>
        </div>
        <div class="toolbar-actions">
          <button class="ghost-button" @click="loadEditor">刷新表单</button>
          <button class="ghost-button" :disabled="refreshingSerials" @click="refreshSerialPorts">
            {{ refreshingSerials ? "刷新串口中..." : "刷新串口" }}
          </button>
          <button class="primary-button" :disabled="saving || loading" @click="saveBoard">
            {{ saving ? "保存中..." : "保存配置" }}
          </button>
        </div>
      </div>

      <div v-if="loading" class="empty-state">正在加载开发板配置...</div>
      <template v-else>
        <p v-if="validationError" class="diagnostic-error">{{ validationError }}</p>

        <section class="form-section">
          <h4>基本信息</h4>
          <div class="form-grid two-columns">
            <label class="field">
              <span>板型</span>
              <input v-model="form.board_type" placeholder="例如 rk3568" />
            </label>
            <label class="field">
              <span>板子 ID</span>
              <input v-model="form.id" placeholder="留空则自动分配 {board type}-{num}" />
              <small class="field-hint">
                编辑已有开发板时留空会保留当前 ID。
              </small>
            </label>
          </div>

          <div class="form-grid two-columns">
            <label class="field">
              <span>标签</span>
              <input v-model="form.tags_text" placeholder="lab, usb" />
            </label>
            <label class="checkbox-field">
              <input v-model="form.disabled" type="checkbox" />
              <span>禁用该开发板</span>
            </label>
          </div>

          <label class="field">
            <span>备注</span>
            <textarea v-model="form.notes" rows="4" />
          </label>
        </section>

        <section class="form-section">
          <h4>串口配置</h4>
          <label class="checkbox-field">
            <input v-model="form.serial_enabled" type="checkbox" />
            <span>启用串口</span>
          </label>

          <div v-if="form.serial_enabled" class="form-grid two-columns">
            <label class="field">
              <span>串口设备</span>
              <select v-model="form.serial_port">
                <option value="">请选择串口设备</option>
                <option
                  v-for="option in serialOptions(form.serial_port)"
                  :key="option.value"
                  :value="option.value"
                >
                  {{ option.label }}
                </option>
              </select>
            </label>
            <label class="field">
              <span>波特率</span>
              <input v-model.number="form.serial_baud_rate" type="number" min="1" />
            </label>
          </div>
        </section>

        <section class="form-section">
          <h4>电源管理</h4>
          <label class="field">
            <span>电源管理类型</span>
            <select v-model="form.power_management_kind">
              <option value="custom">Custom</option>
              <option value="zhongsheng_relay">中盛继电模块</option>
            </select>
          </label>

          <div v-if="form.power_management_kind === 'custom'" class="form-grid two-columns">
            <label class="field">
              <span>开机命令</span>
              <input v-model="form.power_on_cmd" />
            </label>
            <label class="field">
              <span>关机命令</span>
              <input v-model="form.power_off_cmd" />
            </label>
          </div>

          <label v-else class="field">
            <span>继电模块串口</span>
            <select v-model="form.relay_serial_port">
              <option value="">请选择串口设备</option>
              <option
                v-for="option in serialOptions(form.relay_serial_port)"
                :key="option.value"
                :value="option.value"
              >
                {{ option.label }}
              </option>
            </select>
          </label>
        </section>

        <section class="form-section">
          <h4>启动方式</h4>
          <label class="field">
            <span>启动模式</span>
            <select v-model="form.boot_kind">
              <option value="uboot">U-Boot</option>
              <option value="pxe">PXE</option>
            </select>
          </label>

          <template v-if="form.boot_kind === 'uboot'">
            <div class="form-grid two-columns">
              <label class="checkbox-field">
                <input v-model="form.use_tftp" type="checkbox" />
                <span>使用 TFTP 启动</span>
              </label>
            </div>

            <div class="split-grid dtb-config-grid">
              <section class="panel nested-panel dtb-selection-panel">
                <div class="panel-heading compact">
                  <div>
                    <h4>预设 DTB</h4>
                    <p class="field-hint">为当前开发板选择默认使用的设备树文件。</p>
                  </div>
                </div>
                <label class="field">
                  <span>已选择 DTB</span>
                  <select v-model="form.dtb_name">
                    <option value="">不使用预设 DTB</option>
                    <option
                      v-for="option in dtbOptions(form.dtb_name)"
                      :key="option.value"
                      :value="option.value"
                    >
                      {{ option.label }}
                    </option>
                  </select>
                </label>
                <p class="selection-caption">
                  {{ form.dtb_name ? `当前选择：${form.dtb_name}` : "当前未绑定预设 DTB" }}
                </p>
              </section>

              <section class="panel nested-panel dtb-action-panel">
                <div class="panel-heading compact">
                  <div>
                    <h4>新增 DTB</h4>
                    <p class="field-hint">上传新的 DTB 后会自动加入列表，并直接选中。</p>
                  </div>
                </div>
                <button class="primary-button" type="button" @click="openDtbUploadModal">
                  新增 DTB
                </button>
              </section>
            </div>
          </template>

          <label v-else class="field">
            <span>PXE 备注</span>
            <textarea v-model="form.pxe_notes" rows="4" />
          </label>
        </section>

        <div class="danger-zone" v-if="isEditing">
          <h4>危险操作</h4>
          <p>删除会移除对应的单板配置文件，且需要先释放占用该板的 session。</p>
          <button class="danger-button" :disabled="deleting" @click="removeBoard">
            {{ deleting ? "删除中..." : "删除开发板" }}
          </button>
        </div>
      </template>
    </div>
  </section>

  <div
    v-if="showingDtbUploadModal"
    class="modal-overlay"
    @click.self="closeDtbUploadModal"
  >
    <div class="modal-card">
      <div class="panel-heading compact">
        <div>
          <p class="eyebrow">新增 DTB</p>
          <h4>上传并绑定到当前开发板</h4>
        </div>
      </div>

      <div class="form-grid two-columns">
        <label class="field">
          <span>文件名</span>
          <input v-model="dtbUploadName" placeholder="例如 board.dtb" />
        </label>
        <label class="field">
          <span>选择文件</span>
          <input
            ref="dtbFileInput"
            type="file"
            accept=".dtb,application/octet-stream"
            @change="onDtbFileChange"
          />
        </label>
      </div>

      <div class="toolbar-actions modal-actions">
        <button class="ghost-button" type="button" :disabled="uploadingDtb" @click="closeDtbUploadModal">
          取消
        </button>
        <button class="primary-button" type="button" :disabled="uploadingDtb" @click="uploadDtbAndSelect">
          {{ uploadingDtb ? "上传中..." : "上传并选中" }}
        </button>
      </div>
    </div>
  </div>
</template>
