import { computed, ref } from 'vue';

import { getProcessList } from '#/views/system/process/api';

import type { ProcessNoteRow, ProcessRuleRow } from '../constants';
import {
  readProcessSelection,
  writeProcessSelection,
} from '../utils/processSelectionStorage';

export function parseProcessListItems(items: Record<string, any>[]) {
  const level1: ProcessRuleRow[] = [];
  const level2Map: Record<number, ProcessRuleRow[]> = {};
  const notesMap: Record<number, ProcessNoteRow[]> = {};

  for (const item of items) {
    if (item.node_type === 'note') {
      const ruleId = Number(item.pid ?? item.rule_id);
      const note: ProcessNoteRow = {
        ...item,
        real_id: item.real_id ?? Math.abs(Number(item.id)),
        rule_id: ruleId,
        name: item.name ?? item.note,
      };
      if (!notesMap[ruleId]) {
        notesMap[ruleId] = [];
      }
      notesMap[ruleId].push(note);
      continue;
    }

    const rule: ProcessRuleRow = { ...item, node_type: 'rule' };
    if (Number(rule.pid) === 0) {
      level1.push(rule);
      continue;
    }

    const parentId = Number(rule.pid);
    if (!level2Map[parentId]) {
      level2Map[parentId] = [];
    }
    level2Map[parentId].push(rule);
  }

  level1.sort((a, b) => a.id - b.id);
  Object.values(level2Map).forEach((list) => list.sort((a, b) => a.id - b.id));
  Object.values(notesMap).forEach((list) =>
    list.sort((a, b) => a.id - b.id),
  );

  return { level1, level2Map, notesMap };
}

function restoreSelection(
  level1: ProcessRuleRow[],
  level2Map: Record<number, ProcessRuleRow[]>,
  savedLevel1Id: number | null,
  savedMethodId: number | null,
) {
  let level1Id = savedLevel1Id;
  if (!level1Id || !level1.some((item) => item.id === level1Id)) {
    level1Id = level1[0]?.id ?? null;
  }

  const methods = level1Id ? (level2Map[level1Id] ?? []) : [];
  let methodId = savedMethodId;
  if (!methodId || !methods.some((item) => item.id === methodId)) {
    methodId = methods[0]?.id ?? null;
  }

  return { level1Id, methodId };
}

export function useProcessTree() {
  const saved = readProcessSelection();
  const loading = ref(false);
  const keyword = ref('');
  const level1List = ref<ProcessRuleRow[]>([]);
  const level2Map = ref<Record<number, ProcessRuleRow[]>>({});
  const notesMap = ref<Record<number, ProcessNoteRow[]>>({});
  const selectedLevel1Id = ref<number | null>(saved.level1Id);
  const selectedMethodId = ref<number | null>(saved.methodId);

  const filteredLevel1 = computed(() => {
    const kw = keyword.value.trim().toLowerCase();
    if (!kw) {
      return level1List.value;
    }
    return level1List.value.filter((item) => {
      const methods = level2Map.value[item.id] ?? [];
      if (item.name.toLowerCase().includes(kw)) {
        return true;
      }
      return methods.some((method) => {
        if (method.name.toLowerCase().includes(kw)) {
          return true;
        }
        const notes = notesMap.value[method.id] ?? [];
        return notes.some((note) => note.name.toLowerCase().includes(kw));
      });
    });
  });

  const currentMethods = computed(() => {
    if (!selectedLevel1Id.value) {
      return [];
    }
    return level2Map.value[selectedLevel1Id.value] ?? [];
  });

  const selectedMethod = computed(() =>
    currentMethods.value.find((item) => item.id === selectedMethodId.value),
  );

  const currentNotes = computed(() => {
    if (!selectedMethodId.value) {
      return [];
    }
    const kw = keyword.value.trim().toLowerCase();
    const notes = notesMap.value[selectedMethodId.value] ?? [];
    if (!kw) {
      return notes;
    }
    return notes.filter((note) => note.name.toLowerCase().includes(kw));
  });

  const selectedLevel1 = computed(() =>
    level1List.value.find((item) => item.id === selectedLevel1Id.value),
  );

  function persistSelection() {
    writeProcessSelection({
      level1Id: selectedLevel1Id.value,
      methodId: selectedMethodId.value,
    });
  }

  async function loadData() {
    loading.value = true;
    try {
      const res = await getProcessList({
        page: 1,
        pageSize: 500,
      });
      const items = res?.items ?? [];
      const parsed = parseProcessListItems(items);
      level1List.value = parsed.level1;
      level2Map.value = parsed.level2Map;
      notesMap.value = parsed.notesMap;

      const restored = restoreSelection(
        level1List.value,
        level2Map.value,
        selectedLevel1Id.value,
        selectedMethodId.value,
      );
      selectedLevel1Id.value = restored.level1Id;
      selectedMethodId.value = restored.methodId;
      persistSelection();
    } finally {
      loading.value = false;
    }
  }

  function selectLevel1(id: number) {
    selectedLevel1Id.value = id;
    const methods = level2Map.value[id] ?? [];
    selectedMethodId.value = methods[0]?.id ?? null;
    persistSelection();
  }

  function selectMethod(id: number) {
    selectedMethodId.value = id;
    persistSelection();
  }

  function patchRule(id: number, patch: Partial<ProcessRuleRow>) {
    const inLevel1 = level1List.value.find((item) => item.id === id);
    if (inLevel1) {
      Object.assign(inLevel1, patch);
      return;
    }
    for (const list of Object.values(level2Map.value)) {
      const found = list.find((item) => item.id === id);
      if (found) {
        Object.assign(found, patch);
        if (patch.pid !== undefined && Number(patch.pid) === 0) {
          loadData();
        }
        return;
      }
    }
  }

  function patchNote(noteId: number, patch: Partial<ProcessNoteRow>) {
    for (const list of Object.values(notesMap.value)) {
      const found = list.find(
        (item) => item.id === noteId || item.real_id === noteId,
      );
      if (found) {
        Object.assign(found, patch);
        if (patch.name) {
          found.note = patch.name;
        }
        if (patch.rule_id && patch.rule_id !== found.rule_id) {
          loadData();
        }
        return;
      }
    }
  }

  function allLevel2Rules() {
    const result: ProcessRuleRow[] = [];
    for (const list of Object.values(level2Map.value)) {
      result.push(...list);
    }
    return result.sort((a, b) => a.id - b.id);
  }

  return {
    allLevel2Rules,
    currentMethods,
    currentNotes,
    filteredLevel1,
    keyword,
    level1List,
    level2Map,
    loadData,
    loading,
    notesMap,
    patchNote,
    patchRule,
    selectLevel1,
    selectMethod,
    selectedLevel1,
    selectedLevel1Id,
    selectedMethod,
    selectedMethodId,
  };
}
