<script setup lang="ts">
import {
  BriefcaseBusiness,
  Building2,
  ChevronDown,
  ChevronRight,
  FolderTree,
  GitBranch,
  Loader2,
  Plus,
  Save,
} from "@lucide/vue";
import { computed, onMounted, reactive, ref } from "vue";

import {
  createDepartment,
  createPosition,
  listDepartments,
  listPositions,
  updateDepartment,
  updatePosition,
} from "../api/organization";
import { ApiError } from "../api/http";
import type { DepartmentRecord, DepartmentRequest, PositionRecord, PositionRequest } from "../api/types";

type OrganizationNodeType = "department" | "position";
type DetailEditor = "department" | "position";

interface OrganizationTreeNode {
  key: string;
  type: OrganizationNodeType;
  id: number;
  name: string;
  code: string;
  is_active: boolean;
  parentId: number | null;
  departmentId: number | null;
  children: OrganizationTreeNode[];
}

interface OrganizationTreeRow {
  node: OrganizationTreeNode;
  depth: number;
}

const departments = ref<DepartmentRecord[]>([]);
const positions = ref<PositionRecord[]>([]);
const loading = ref(false);
const savingDepartment = ref(false);
const savingPosition = ref(false);
const editingDepartmentId = ref<number | null>(null);
const editingPositionId = ref<number | null>(null);
const editingPositionCode = ref("");
const currentEditor = ref<DetailEditor>("department");
const selectedNodeKey = ref("");
const expandedDepartmentIds = ref<Set<number>>(new Set());
const hasInitializedExpansion = ref(false);
const errorMessage = ref("");
const successMessage = ref("");

const departmentForm = reactive<DepartmentRequest>({
  parent_id: null,
  department_code: "",
  name: "",
  sort_order: 0,
  is_active: true,
  remark: "",
});

const positionForm = reactive<PositionRequest>({
  department_id: 0,
  name: "",
  sort_order: 0,
  is_active: true,
  remark: "",
});

const sortedDepartments = computed(() => [...departments.value].sort(sortByOrderThenId));
const sortedPositions = computed(() => [...positions.value].sort(sortByOrderThenId));
const activeDepartments = computed(() => sortedDepartments.value.filter((item) => item.is_active));
const activePositions = computed(() => sortedPositions.value.filter((item) => item.is_active));

const organizationTree = computed<OrganizationTreeNode[]>(() => {
  const departmentNodeMap = new Map<number, OrganizationTreeNode>();
  const roots: OrganizationTreeNode[] = [];

  for (const department of sortedDepartments.value) {
    departmentNodeMap.set(department.id, {
      key: departmentKey(department.id),
      type: "department",
      id: department.id,
      name: department.name,
      code: department.department_code,
      is_active: department.is_active,
      parentId: department.parent_id,
      departmentId: department.id,
      children: [],
    });
  }

  for (const department of sortedDepartments.value) {
    const node = departmentNodeMap.get(department.id);
    if (!node) {
      continue;
    }
    const parentNode = department.parent_id ? departmentNodeMap.get(department.parent_id) : null;
    if (parentNode) {
      parentNode.children.push(node);
    } else {
      roots.push(node);
    }
  }

  for (const position of sortedPositions.value) {
    const parentNode = departmentNodeMap.get(position.department_id);
    if (!parentNode) {
      continue;
    }
    parentNode.children.push({
      key: positionKey(position.id),
      type: "position",
      id: position.id,
      name: position.name,
      code: position.position_code,
      is_active: position.is_active,
      parentId: position.department_id,
      departmentId: position.department_id,
      children: [],
    });
  }

  return roots;
});

const allTreeNodes = computed(() => flattenAllNodes(organizationTree.value));
const selectedNode = computed(() => allTreeNodes.value.find((node) => node.key === selectedNodeKey.value) || null);
const visibleTreeRows = computed<OrganizationTreeRow[]>(() => flattenVisibleNodes(organizationTree.value));

const availableParentDepartments = computed(() => {
  const excludedIds = editingDepartmentId.value ? descendantDepartmentIds(editingDepartmentId.value) : new Set<number>();
  if (editingDepartmentId.value) {
    excludedIds.add(editingDepartmentId.value);
  }
  return sortedDepartments.value.filter((department) => !excludedIds.has(department.id));
});

const actionDepartmentId = computed(() => {
  if (selectedNode.value?.type === "department") {
    return selectedNode.value.id;
  }
  if (selectedNode.value?.type === "position") {
    return selectedNode.value.departmentId || 0;
  }
  if (editingDepartmentId.value) {
    return editingDepartmentId.value;
  }
  return positionForm.department_id || departmentForm.parent_id || 0;
});

const selectedDepartment = computed(() => {
  if (!actionDepartmentId.value) {
    return null;
  }
  return departments.value.find((department) => department.id === actionDepartmentId.value) || null;
});

const selectedDepartmentChildren = computed(() => {
  if (!actionDepartmentId.value) {
    return [];
  }
  return sortedDepartments.value.filter((department) => department.parent_id === actionDepartmentId.value);
});

const selectedDepartmentPositions = computed(() => {
  if (!actionDepartmentId.value) {
    return [];
  }
  return sortedPositions.value.filter((position) => position.department_id === actionDepartmentId.value);
});

const detailTitle = computed(() => {
  if (currentEditor.value === "department") {
    return editingDepartmentId.value ? "部门详情" : "新增部门";
  }
  return editingPositionId.value ? "岗位详情" : "新增岗位";
});

const detailSubtitle = computed(() => {
  if (currentEditor.value === "department") {
    return editingDepartmentId.value ? "调整部门编码、父级和启用状态" : "新增部门时可直接指定上级部门";
  }
  return editingPositionId.value ? "调整岗位名称、所属部门和启用状态" : "新增岗位会挂到当前选中的部门下";
});

onMounted(loadData);

async function loadData(): Promise<void> {
  loading.value = true;
  errorMessage.value = "";
  try {
    const [departmentRows, positionRowsData] = await Promise.all([
      listDepartments(false),
      listPositions(undefined, false),
    ]);
    departments.value = departmentRows;
    positions.value = positionRowsData;
    reconcileExpandedDepartments(departmentRows);
    syncSelectionAfterLoad();
  } catch (error) {
    errorMessage.value = error instanceof ApiError ? error.message : "组织架构加载失败";
  } finally {
    loading.value = false;
  }
}

async function submitDepartment(): Promise<void> {
  savingDepartment.value = true;
  errorMessage.value = "";
  successMessage.value = "";
  try {
    const department = editingDepartmentId.value
      ? await updateDepartment(editingDepartmentId.value, normalizedDepartment())
      : await createDepartment(normalizedDepartment());
    selectedNodeKey.value = departmentKey(department.id);
    successMessage.value = editingDepartmentId.value ? "部门已更新" : "部门已新增";
    await loadData();
  } catch (error) {
    errorMessage.value = error instanceof ApiError ? error.message : "部门保存失败";
  } finally {
    savingDepartment.value = false;
  }
}

async function submitPosition(): Promise<void> {
  if (!positionForm.department_id) {
    errorMessage.value = "请选择岗位所属部门";
    return;
  }
  savingPosition.value = true;
  errorMessage.value = "";
  successMessage.value = "";
  try {
    const position = editingPositionId.value
      ? await updatePosition(editingPositionId.value, normalizedPosition())
      : await createPosition(normalizedPosition());
    selectedNodeKey.value = positionKey(position.id);
    successMessage.value = editingPositionId.value ? "岗位已更新" : "岗位已新增";
    await loadData();
  } catch (error) {
    errorMessage.value = error instanceof ApiError ? error.message : "岗位保存失败";
  } finally {
    savingPosition.value = false;
  }
}

function selectTreeNode(node: OrganizationTreeNode): void {
  if (node.type === "department") {
    const department = departments.value.find((item) => item.id === node.id);
    if (department) {
      selectDepartment(department);
    }
    return;
  }
  const position = positions.value.find((item) => item.id === node.id);
  if (position) {
    selectPosition(position);
  }
}

function selectDepartment(department: DepartmentRecord): void {
  currentEditor.value = "department";
  selectedNodeKey.value = departmentKey(department.id);
  editingDepartmentId.value = department.id;
  editingPositionId.value = null;
  editingPositionCode.value = "";
  expandDepartmentPath(department.id);
  Object.assign(departmentForm, {
    parent_id: department.parent_id,
    department_code: department.department_code,
    name: department.name,
    sort_order: department.sort_order,
    is_active: department.is_active,
    remark: department.remark,
  });
}

function selectPosition(position: PositionRecord): void {
  currentEditor.value = "position";
  selectedNodeKey.value = positionKey(position.id);
  editingPositionId.value = position.id;
  editingPositionCode.value = position.position_code;
  editingDepartmentId.value = null;
  expandDepartmentPath(position.department_id);
  Object.assign(positionForm, {
    department_id: position.department_id,
    name: position.name,
    sort_order: position.sort_order,
    is_active: position.is_active,
    remark: position.remark,
  });
}

function startNewRootDepartment(): void {
  currentEditor.value = "department";
  selectedNodeKey.value = "new-department";
  resetDepartmentForm();
}

function startNewChildDepartment(): void {
  const parentId = actionDepartmentId.value;
  currentEditor.value = "department";
  selectedNodeKey.value = "new-child-department";
  resetDepartmentForm();
  departmentForm.parent_id = parentId || null;
  if (parentId) {
    expandDepartmentPath(parentId);
  }
}

function startNewPosition(): void {
  const departmentId = actionDepartmentId.value || activeDepartments.value[0]?.id || 0;
  currentEditor.value = "position";
  selectedNodeKey.value = "new-position";
  resetPositionForm();
  positionForm.department_id = departmentId;
  if (departmentId) {
    expandDepartmentPath(departmentId);
  }
}

function resetDepartmentForm(): void {
  editingDepartmentId.value = null;
  Object.assign(departmentForm, {
    parent_id: null,
    department_code: "",
    name: "",
    sort_order: 0,
    is_active: true,
    remark: "",
  });
}

function resetPositionForm(): void {
  editingPositionId.value = null;
  editingPositionCode.value = "";
  Object.assign(positionForm, {
    department_id: 0,
    name: "",
    sort_order: 0,
    is_active: true,
    remark: "",
  });
}

function toggleDepartment(node: OrganizationTreeNode): void {
  if (node.type !== "department") {
    return;
  }
  const nextExpanded = new Set(expandedDepartmentIds.value);
  if (nextExpanded.has(node.id)) {
    nextExpanded.delete(node.id);
  } else {
    nextExpanded.add(node.id);
  }
  expandedDepartmentIds.value = nextExpanded;
}

function expandAllDepartments(): void {
  expandedDepartmentIds.value = new Set(departments.value.map((department) => department.id));
}

function collapseAllDepartments(): void {
  expandedDepartmentIds.value = new Set();
}

function normalizedDepartment(): DepartmentRequest {
  return {
    parent_id: departmentForm.parent_id || null,
    department_code: departmentForm.department_code.trim(),
    name: departmentForm.name.trim(),
    sort_order: Number(departmentForm.sort_order || 0),
    is_active: departmentForm.is_active,
    remark: departmentForm.remark.trim(),
  };
}

function normalizedPosition(): PositionRequest {
  return {
    department_id: Number(positionForm.department_id),
    position_code: editingPositionCode.value,
    name: positionForm.name.trim(),
    sort_order: Number(positionForm.sort_order || 0),
    is_active: positionForm.is_active,
    remark: positionForm.remark.trim(),
  };
}

function syncSelectionAfterLoad(): void {
  const node = allTreeNodes.value.find((item) => item.key === selectedNodeKey.value);
  if (node) {
    selectTreeNode(node);
    return;
  }
  if (sortedDepartments.value.length > 0) {
    selectDepartment(sortedDepartments.value[0]);
  }
}

function reconcileExpandedDepartments(nextDepartments: DepartmentRecord[]): void {
  const availableIds = new Set(nextDepartments.map((department) => department.id));
  if (!hasInitializedExpansion.value) {
    expandedDepartmentIds.value = new Set(availableIds);
    hasInitializedExpansion.value = true;
    return;
  }
  expandedDepartmentIds.value = new Set(
    [...expandedDepartmentIds.value].filter((departmentId) => availableIds.has(departmentId)),
  );
}

function flattenAllNodes(nodes: OrganizationTreeNode[]): OrganizationTreeNode[] {
  return nodes.flatMap((node) => [node, ...flattenAllNodes(node.children)]);
}

function flattenVisibleNodes(nodes: OrganizationTreeNode[], depth = 0): OrganizationTreeRow[] {
  const rows: OrganizationTreeRow[] = [];
  for (const node of nodes) {
    rows.push({ node, depth });
    if (node.type === "department" && expandedDepartmentIds.value.has(node.id)) {
      rows.push(...flattenVisibleNodes(node.children, depth + 1));
    }
  }
  return rows;
}

function expandDepartmentPath(departmentId: number): void {
  const nextExpanded = new Set(expandedDepartmentIds.value);
  let current = departments.value.find((department) => department.id === departmentId) || null;
  while (current) {
    nextExpanded.add(current.id);
    current = current.parent_id
      ? departments.value.find((department) => department.id === current?.parent_id) || null
      : null;
  }
  expandedDepartmentIds.value = nextExpanded;
}

function descendantDepartmentIds(departmentId: number): Set<number> {
  const result = new Set<number>();
  const collect = (parentId: number): void => {
    for (const department of departments.value) {
      if (department.parent_id === parentId) {
        result.add(department.id);
        collect(department.id);
      }
    }
  };
  collect(departmentId);
  return result;
}

function departmentOptionLabel(department: DepartmentRecord): string {
  return departmentPath(department.id).join(" / ");
}

function departmentPath(departmentId: number): string[] {
  const path: string[] = [];
  let current = departments.value.find((department) => department.id === departmentId) || null;
  while (current) {
    path.unshift(current.name);
    current = current.parent_id
      ? departments.value.find((department) => department.id === current?.parent_id) || null
      : null;
  }
  return path;
}

function treeNodeStyle(depth: number): Record<string, string> {
  return { "--tree-depth": String(depth) };
}

function departmentKey(id: number): string {
  return `department-${id}`;
}

function positionKey(id: number): string {
  return `position-${id}`;
}

function sortByOrderThenId<T extends { sort_order: number; id: number }>(left: T, right: T): number {
  return left.sort_order - right.sort_order || left.id - right.id;
}
</script>

<template>
  <div class="view-stack">
    <header class="page-header">
      <div>
        <h1>组织架构</h1>
        <p>用树状关系维护部门上下级和部门下岗位，员工维护会按这里的关系联动。</p>
      </div>
    </header>

    <section class="organization-summary-strip">
      <div>
        <Building2 :size="18" aria-hidden="true" />
        <span>部门</span>
        <strong>{{ departments.length }}</strong>
        <small>{{ activeDepartments.length }} 个启用</small>
      </div>
      <div>
        <GitBranch :size="18" aria-hidden="true" />
        <span>岗位</span>
        <strong>{{ positions.length }}</strong>
        <small>{{ activePositions.length }} 个启用</small>
      </div>
      <div>
        <FolderTree :size="18" aria-hidden="true" />
        <span>当前部门</span>
        <strong>{{ selectedDepartment?.name || "-" }}</strong>
        <small>{{ selectedDepartmentPositions.length }} 个直属岗位</small>
      </div>
    </section>

    <p v-if="errorMessage" class="form-error">{{ errorMessage }}</p>
    <p v-if="successMessage" class="form-success">{{ successMessage }}</p>

    <section class="organization-tree-layout">
      <aside class="panel organization-tree-panel">
        <div class="panel-header">
          <div>
            <h2>组织树</h2>
            <p>{{ departments.length }} 个部门，{{ positions.length }} 个岗位</p>
          </div>
          <div class="organization-tree-tools">
            <button class="link-button" type="button" @click="expandAllDepartments">展开</button>
            <button class="link-button muted" type="button" @click="collapseAllDepartments">收起</button>
          </div>
        </div>

        <div class="organization-tree" aria-label="组织架构树">
          <div v-if="loading" class="organization-tree-empty">
            <Loader2 class="spin" :size="18" aria-hidden="true" />
            <span>正在加载组织架构</span>
          </div>
          <div v-else-if="visibleTreeRows.length === 0" class="organization-tree-empty">
            <span>暂无组织架构，请先新增部门</span>
          </div>
          <button
            v-for="row in visibleTreeRows"
            v-else
            :key="row.node.key"
            class="tree-node"
            :class="[
              `tree-node-${row.node.type}`,
              {
                'is-selected': selectedNodeKey === row.node.key,
                'is-inactive': !row.node.is_active,
              },
            ]"
            :style="treeNodeStyle(row.depth)"
            type="button"
            @click="selectTreeNode(row.node)"
          >
            <span
              v-if="row.node.type === 'department' && row.node.children.length"
              class="tree-toggle"
              role="button"
              tabindex="-1"
              @click.stop="toggleDepartment(row.node)"
            >
              <ChevronDown v-if="expandedDepartmentIds.has(row.node.id)" :size="15" aria-hidden="true" />
              <ChevronRight v-else :size="15" aria-hidden="true" />
            </span>
            <span v-else class="tree-toggle is-placeholder" aria-hidden="true"></span>
            <span class="tree-node-icon">
              <Building2 v-if="row.node.type === 'department'" :size="16" aria-hidden="true" />
              <BriefcaseBusiness v-else :size="16" aria-hidden="true" />
            </span>
            <span class="tree-node-main">
              <strong>{{ row.node.name }}</strong>
              <small>{{ row.node.code }}</small>
            </span>
            <span class="status-chip" :class="row.node.is_active ? 'green' : 'red'">
              {{ row.node.is_active ? "启用" : "停用" }}
            </span>
          </button>
        </div>
      </aside>

      <section class="panel organization-detail-panel">
        <div class="panel-header organization-detail-header">
          <div>
            <h2>{{ detailTitle }}</h2>
            <p>{{ detailSubtitle }}</p>
          </div>
          <div class="organization-detail-actions">
            <button class="secondary-button compact-button" type="button" @click="startNewRootDepartment">
              <Plus :size="16" aria-hidden="true" />
              <span>新增部门</span>
            </button>
            <button
              class="secondary-button compact-button"
              type="button"
              :disabled="!actionDepartmentId"
              @click="startNewChildDepartment"
            >
              <Plus :size="16" aria-hidden="true" />
              <span>新增下级</span>
            </button>
            <button
              class="primary-button compact-button"
              type="button"
              :disabled="!actionDepartmentId && activeDepartments.length === 0"
              @click="startNewPosition"
            >
              <Plus :size="16" aria-hidden="true" />
              <span>新增岗位</span>
            </button>
          </div>
        </div>

        <div v-if="selectedDepartment" class="organization-node-summary">
          <div>
            <span>上级部门</span>
            <strong>{{ selectedDepartment.parent_id ? departmentPath(selectedDepartment.parent_id).join(" / ") : "无上级" }}</strong>
          </div>
          <div>
            <span>下级部门</span>
            <strong>{{ selectedDepartmentChildren.length }} 个</strong>
          </div>
          <div>
            <span>直属岗位</span>
            <strong>{{ selectedDepartmentPositions.length }} 个</strong>
          </div>
        </div>

        <form
          v-if="currentEditor === 'department'"
          class="form-grid compact-form organization-editor-form"
          @submit.prevent="submitDepartment"
        >
          <label class="field">
            <span>部门编码</span>
            <input v-model="departmentForm.department_code" required maxlength="64" type="text" />
          </label>
          <label class="field">
            <span>部门名称</span>
            <input v-model="departmentForm.name" required maxlength="128" type="text" />
          </label>
          <label class="field">
            <span>父级部门</span>
            <select v-model.number="departmentForm.parent_id">
              <option :value="null">无上级部门</option>
              <option v-for="department in availableParentDepartments" :key="department.id" :value="department.id">
                {{ departmentOptionLabel(department) }}
              </option>
            </select>
          </label>
          <label class="field">
            <span>排序</span>
            <input v-model.number="departmentForm.sort_order" type="number" />
          </label>
          <label class="checkbox-card span-row">
            <input v-model="departmentForm.is_active" type="checkbox" />
            <span>启用部门</span>
          </label>
          <label class="field span-row">
            <span>备注</span>
            <textarea v-model="departmentForm.remark" />
          </label>
          <div class="form-actions align-right span-row">
            <button class="primary-button" type="submit" :disabled="savingDepartment">
              <Loader2 v-if="savingDepartment" class="spin" :size="18" aria-hidden="true" />
              <Save v-else :size="18" aria-hidden="true" />
              <span>{{ savingDepartment ? "保存中" : editingDepartmentId ? "保存部门" : "创建部门" }}</span>
            </button>
          </div>
        </form>

        <form v-else class="form-grid compact-form organization-editor-form" @submit.prevent="submitPosition">
          <label class="field">
            <span>所属部门</span>
            <select v-model.number="positionForm.department_id" required>
              <option :value="0">请选择部门</option>
              <option v-for="department in activeDepartments" :key="department.id" :value="department.id">
                {{ departmentOptionLabel(department) }}
              </option>
            </select>
          </label>
          <label class="field">
            <span>岗位编码</span>
            <input :value="editingPositionCode || '保存后自动生成'" readonly type="text" />
          </label>
          <label class="field">
            <span>岗位名称</span>
            <input v-model="positionForm.name" required maxlength="128" type="text" />
          </label>
          <label class="field">
            <span>排序</span>
            <input v-model.number="positionForm.sort_order" type="number" />
          </label>
          <label class="checkbox-card span-row">
            <input v-model="positionForm.is_active" type="checkbox" />
            <span>启用岗位</span>
          </label>
          <label class="field span-row">
            <span>备注</span>
            <textarea v-model="positionForm.remark" />
          </label>
          <div class="form-actions align-right span-row">
            <button class="primary-button" type="submit" :disabled="savingPosition">
              <Loader2 v-if="savingPosition" class="spin" :size="18" aria-hidden="true" />
              <Save v-else :size="18" aria-hidden="true" />
              <span>{{ savingPosition ? "保存中" : editingPositionId ? "保存岗位" : "创建岗位" }}</span>
            </button>
          </div>
        </form>
      </section>
    </section>
  </div>
</template>
