<template>
	<fs-page class="borrow-page"> 
		<!-- <fs-page>  -->
		<fs-crud ref="crudRef" v-bind="crudBinding" />
		<BorrowTypeSelect v-model:visible="showBorrowTypeDialog" @select="onBorrowTypeSelected" />
		<CommonBorrow 
			v-if="showCommonBorrowDialog" 
			v-model:visible="showCommonBorrowDialog" 
			:modelValue="borrowForm" 
			@submit="handleBorrowSubmit"
			@refresh="crudExpose.doRefresh()"
		/>
		<ClassroomBorrow
			v-if="showClassroomBorrowDialog"
			v-model:visible="showClassroomBorrowDialog"
			:modelValue="borrowForm"
			:lastFormSnapshot="lastFormSnapshot"
			@update:lastFormSnapshot="val => lastFormSnapshot = val"
			@submit="handleBorrowSubmit"
		/>
		<SpecialBorrow v-if="showSpecialBorrowDialog" v-model:visible="showSpecialBorrowDialog" :modelValue="borrowForm" @submit="handleBorrowSubmit" />
		<CollectEquipmentDialog  v-model:visible="showCollectDialog" :modelValue="borrowForm" @submit="handleCollectSubmit" />
		<SettlementDialog  v-model:visible="showSettlementDialog" :modelValue="borrowForm" />
	</fs-page>
</template>
<script lang="ts" setup name="borrow">
import { ref, onMounted, onActivated, onBeforeUnmount, nextTick, provide } from 'vue';
import { useFs } from '@fast-crud/fast-crud';
import { createCrudOptions } from './crud';
// import { GetPermission } from './api';
// import { handleColumnPermission } from '/@/utils/columnPermission';
import BorrowTypeSelect from './component/BorrowTypeSelect/index.vue';
 import CommonBorrow from './component/CommonBorrow/index.vue';
import ClassroomBorrow from './component/ClassroomBorrow/index.vue';
import SpecialBorrow from './component/SpecialBorrow/index.vue';
import CollectEquipmentDialog from './component/CollectEquipment/index.vue';
import SettlementDialog from './component/CollectEquipment/SettlementDialog.vue';
import * as api from './api';
import { ElMessage } from 'element-plus';
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
import type { LocationQuery } from 'vue-router';

const route = useRoute();

function firstQueryString(v: unknown): string {
	if (v == null) return '';
	if (Array.isArray(v)) {
		const x = v[0];
		return x != null ? String(x) : '';
	}
	return String(v);
}

const BORROW_LIST_DEBUG = true;

/** 路由 query → 借用列表搜索表单（与 crud 列 status / status__in 一致；禁止重复 status 键） */
function buildBorrowListSearchFormFromRoute(q: LocationQuery) {
	const raw = firstQueryString(
		(q as Record<string, unknown>).status__in ?? q.status_in ?? q.status
	).trim();
	if (BORROW_LIST_DEBUG) {
		// eslint-disable-next-line no-console
		console.log('[borrow/list] 路由 query', { ...q }, '→ 原始 status 链:', raw);
	}
	if (raw === '') {
		const empty = { status: undefined, status__in: undefined };
		if (BORROW_LIST_DEBUG) {
			// eslint-disable-next-line no-console
			console.log('[borrow/list] 无 status 条件 → doSearch form', empty);
		}
		return empty;
	}
	/* 多状态：逗号分隔，对应表单列 status__in */
	if (raw.includes(',')) {
		const f = { status: undefined, status__in: raw };
		if (BORROW_LIST_DEBUG) {
			// eslint-disable-next-line no-console
			console.log('[borrow/list] 多状态（含逗号）→ form.status__in =', f.status__in);
		}
		return f;
	}
	const num = Number(raw);
	if (Number.isFinite(num) && num > 0) {
		const f = { status: num, status__in: undefined };
		if (BORROW_LIST_DEBUG) {
			// eslint-disable-next-line no-console
			console.log('[borrow/list] 单状态（数字）→ form.status =', f.status);
		}
		return f;
	}
	const f = { status: raw, status__in: undefined };
	if (BORROW_LIST_DEBUG) {
		// eslint-disable-next-line no-console
		console.log('[borrow/list] 单状态（非纯数字）→ form.status =', f.status);
	}
	return f;
}

const { crudBinding, crudRef, crudExpose } = useFs({ createCrudOptions });
const showBorrowTypeDialog = ref(false);
const showCommonBorrowDialog = ref(false);
const showClassroomBorrowDialog = ref(false);
const showSpecialBorrowDialog = ref(false);
const showCollectDialog = ref(false);
const borrowForm = ref({});
const showSettlementDialog = ref(false);

/** keep-alive 下首次进入会先后触发 onMounted 与 onActivated，避免重复 doSearch */
const skipNextActivatedBorrowSearch = ref(false);

/** 与 onActivated 协调：避免 keep-alive 首次 onMounted + onActivated 连续请求两次 */
function applyRouteSearchToCrud() {
	skipNextActivatedBorrowSearch.value = true;
	crudExpose.doSearch({
		form: buildBorrowListSearchFormFromRoute(route.query),
	});
}

const lastFormSnapshot = ref({});
// provide('lastFormSnapshot', lastFormSnapshot);

/** 在响应中递归查找「疑似借用单」主键；expectedBorrowType 为 1 课堂 / 2 特殊 等，与列表性质一致，避免误取 user.id */
function findBorrowApplicationIdInResponseTree(
	res: any,
	expectedBorrowType: number
): string | number | null {
	const s = new WeakSet<object>();
	const want = Number(expectedBorrowType);
	function walk(n: any, depth: number): string | number | null {
		if (n == null || depth > 8) return null;
		if (typeof n !== 'object') return null;
		if (s.has(n as object) && !Array.isArray(n)) return null;
		s.add(n as object);
		if (Array.isArray(n)) {
			for (const item of n) {
				const f = walk(item, depth + 1);
				if (f != null) return f;
			}
			return null;
		}
		const o = n as any;
		if (o.id != null) {
			const hasNo = o.application_no != null && String(o.application_no).trim() !== '';
			const hasBt = o.borrow_type != null;
			const hasPurpose = o.purpose != null && String(o.purpose).trim() !== '';
			const nbt = Number(o.borrow_type);
			if (
				hasNo ||
				(hasBt &&
					hasPurpose &&
					!Number.isNaN(nbt) &&
					nbt === want)
			) {
				return o.id;
			}
		}
		for (const v of Object.values(n)) {
			if (v && typeof v === 'object') {
				const f = walk(v, depth + 1);
				if (f != null) return f;
			}
		}
		return null;
	}
	return walk(res, 0);
}

/** 从「新建借用单」POST 标准返回中尽量解析出新建单 id（兼容 data 为对象/数字/数组及常见字段名） */
function parseNewBorrowApplicationId(res: any): string | number | null {
	if (!res) return null;
	if (res.id != null) return res.id;
	const d = res.data;
	if (d == null) return null;
	if (typeof d === 'number') return d;
	if (typeof d === 'string' && d.trim() !== '' && !Number.isNaN(Number(d))) {
		return Number(d);
	}
	if (Array.isArray(d) && d.length > 0) {
		const r0 = d[0] as any;
		if (r0?.id != null) return r0.id;
	}
	if (typeof d === 'object') {
		const id =
			d.id ?? d.pk ?? d.application_id ?? d.applicationId ?? d.bid;
		if (id != null) return id;
		if (Array.isArray((d as any).results) && (d as any).results[0]?.id != null) {
			return (d as any).results[0].id;
		}
		const inner = d.data;
		if (inner && typeof inner === 'object' && (inner as any).id != null) return (inner as any).id;
	}
	return null;
}

function listResponseRecords(lr: any): any[] {
	const d = lr?.data;
	if (!d) return [];
	if (Array.isArray(d.items)) return d.items;
	if (Array.isArray(d.results)) return d.results;
	if (Array.isArray(d.records)) return d.records;
	if (Array.isArray(d)) return d;
	return [];
}

/** 用关键字搜索 + 单号 / 用途 等在列表中匹配新建单；borrowType 与借用性质（1 课堂 2 特殊…）一致 */
async function searchBorrowIdByList(params: {
	search?: string;
	formPurpose?: string;
	formExpectedStart?: string;
	borrowType: number;
}): Promise<string | number | null> {
	const { search, formPurpose, formExpectedStart, borrowType } = params;
	const base = {
		page: 1,
		limit: 30,
		borrow_type: Number(borrowType),
		ordering: '-create_datetime',
	} as Record<string, any>;
	try {
		if (search && String(search).trim() !== '') {
			const lr: any = await api.GetList({
				...base,
				search: String(search).trim(),
			} as any);
			const rows = listResponseRecords(lr);
			if (search) {
				const t = String(search).trim();
				const byNo = rows.find(
					(r: any) => r && String(r.application_no) === t
				);
				if (byNo?.id != null) return byNo.id;
			}
		}
		// 无单号时：取同性质借用最近一页，用「用途」+ 预计开始日（若有）弱匹配
		const lr2: any = await api.GetList(base as any);
		const rows = listResponseRecords(lr2);
		if (!rows.length) return null;
		if (formPurpose) {
			const p = String(formPurpose).trim();
			const m = rows.find((r: any) => r && String(r.purpose) === p);
			if (m?.id != null) return m.id;
		}
		if (formExpectedStart) {
			const day = String(formExpectedStart).slice(0, 10);
			const m = rows.find(
				(r: any) =>
					r &&
					r.expected_start_time &&
					String(r.expected_start_time).slice(0, 10) === day
			);
			if (m?.id != null) return m.id;
		}
		// 新建立即查询时，多并发下非 100% 可靠；与后端约定在 POST 中回 id 可彻底避免
		return rows[0]?.id ?? null;
	} catch {
		return null;
	}
}

/**
 * 从 POST 返回 + 表单快照解析新建单主键，供直接打开「领取」（课堂/特殊等，由 borrow_type 区分）
 */
async function resolveNewBorrowApplicationIdAfterAdd(
	res: any,
	submitted: Record<string, any>
): Promise<string | number | null> {
	const borrowType = Number(submitted?.borrow_type);
	let id = parseNewBorrowApplicationId(res);
	if (id != null) return id;
	if (!Number.isNaN(borrowType)) {
		id = findBorrowApplicationIdInResponseTree(res, borrowType);
		if (id != null) return id;
	}
	const d = res?.data;
	const appNoFromRes =
		d && typeof d === 'object' ? d.application_no ?? d.applicationNo : null;
	if (appNoFromRes && String(appNoFromRes).trim() !== '' && !Number.isNaN(borrowType)) {
		id = await searchBorrowIdByList({
			search: String(appNoFromRes).trim(),
			borrowType,
		});
		if (id != null) return id;
	}
	if (submitted?.application_no && !Number.isNaN(borrowType)) {
		id = await searchBorrowIdByList({
			search: String(submitted.application_no),
			borrowType,
		});
		if (id != null) return id;
	}
	return await searchBorrowIdByList({
		formPurpose: submitted?.purpose,
		formExpectedStart: submitted?.expected_start_time,
		borrowType: Number.isNaN(borrowType) ? 1 : borrowType,
	});
}

/** 与 crud 行操作「领取」一致：仅 status===2 时可领用；待审批等为其它值 */
const BORROW_STATUS_PENDING_APPROVAL = 1;
const BORROW_STATUS_READY_COLLECT = 2;

function parseStatusFromCreateResponse(res: any): number | null {
	if (!res) return null;
	const toNum = (v: unknown) => {
		if (v == null || v === '') return null;
		const n = Number(v);
		return Number.isFinite(n) ? n : null;
	};
	const d = res.data;
	if (d != null && typeof d === 'object' && !Array.isArray(d)) {
		const s = toNum((d as Record<string, unknown>).status);
		if (s != null) return s;
	}
	return null;
}

async function resolveBorrowStatusAfterCreate(
	res: any,
	newId: string | number
): Promise<number | null> {
	const fromRes = parseStatusFromCreateResponse(res);
	if (fromRes != null) return fromRes;
	try {
		const detail: any = await api.GetApplicationDetail(Number(newId));
		if (detail?.code === 2000 && detail?.data?.status != null) {
			return Number(detail.data.status);
		}
	} catch {
		/* empty */
	}
	return null;
}

function onBorrowTypeSelected(type: number, mode: 'view' | 'edit' | 'add' |'collect',record?: any) {
	showBorrowTypeDialog.value = false;
	// 必须先同步写入 borrowForm，再打开子弹窗；若在 nextTick 中赋值，子组件挂载时仍拿到上一次的查看/编辑数据，会误拉详情并残留在表单中
	borrowForm.value = { ...(record || {}), borrow_type: type, mode };
	if (type === 1) {
		if (mode === 'view') {
			showCollectDialog.value = true;
		} else {
			showClassroomBorrowDialog.value = true;
		}
	} else if (type === 2) {
		if (mode === 'view') {
			showCollectDialog.value = true;
		} else {
			showSpecialBorrowDialog.value = true;
		}
	} else if (type === 0) {
		if (mode === 'view') {
			showCollectDialog.value = true;
		} else {
			showCommonBorrowDialog.value = true;
		}
	}
}

async function handleBorrowSubmit(formData: any) {
	try {
		if (formData.mode === 'edit') {
			await api.UpdateObj(formData);
			ElMessage.success('编辑成功');
		} else {
			const res: any = await api.AddObj(formData);
			ElMessage.success('添加成功');
			// 课堂(1) / 特殊(2)：仅当已处于「可领取」状态时再自动打开领取（待审批如多步 workflow 不会误开）
			const addBorrowType = Number(formData.borrow_type);
			if (addBorrowType === 1 || addBorrowType === 2) {
				const newId = await resolveNewBorrowApplicationIdAfterAdd(res, formData);
				if (newId != null) {
					const status = await resolveBorrowStatusAfterCreate(res, newId);
					if (status === BORROW_STATUS_READY_COLLECT) {
						borrowForm.value = {
							id: newId,
							borrow_type: addBorrowType,
							mode: 'collect',
							collectInitialTab: 'second',
						};
						showCollectDialog.value = true;
					} else if (status === BORROW_STATUS_PENDING_APPROVAL) {
						ElMessage.info('申请已提交，审批通过后可从列表点击「领取」办理领用');
					} else {
						ElMessage.info('申请已提交，请稍后在列表中查看；满足领用条件后可点击「领取」');
					}
				} else {
					console.warn(
						'[borrow] 新建借用后仍无法确定单主键，请让 POST /application/ 在 data 中返回 id；可暂从列表点击「领取」',
						res
					);
					ElMessage.info('已新建成功，请从下方列表中点击该单的「领取」');
				}
			}
		}
		
		// 刷新列表
		crudRef.value && crudRef.value.doRefresh && crudRef.value.doRefresh();	
		crudExpose.doRefresh();

	} catch (e) {
		// 错误处理
		console.error(formData.mode === 'edit' ? '编辑失败' : '提交失败', e);
		ElMessage.error(formData.mode === 'edit' ? '编辑失败' : '提交失败');
	}
}

async function handleCollectSubmit(formData: any) {
	 try {
		crudExpose.doRefresh();
	 } catch (e) {
		console.error('提交失败', e);
	}
}

async function handleCollect(e: CustomEvent) {
	const row = e.detail;
	console.log("row:::",row);
	borrowForm.value = { ...row, mode: 'collect' };
	showCollectDialog.value = true;
	console.log("showCollectDialog:::",showCollectDialog.value);
}


async function handleReturn(e: CustomEvent) {
	const row = e.detail;
	console.log("row:::",row);
	borrowForm.value = { ...row, mode: 'return' };
	showCollectDialog.value = true;
	console.log("showReturnDialog:::",showCollectDialog.value);
}

async function handleView(e: CustomEvent) {
	const row = e.detail;
	onBorrowTypeSelected(row.borrow_type, 'view',row);
}
async function handleEdit(e: CustomEvent) {
	const row = e.detail;
	onBorrowTypeSelected(row.borrow_type, 'edit',row);
}
async function handleRemove(e: CustomEvent) {
	const row = e.detail;
	onBorrowTypeSelected(row.borrow_type);
}
async function handleSettlement(e: CustomEvent) {
	const row = e.detail;
	console.log("row:::",row);
	try {
		// 获取申请详情，避免直接使用行内简略数据
		const res: any = await api.GetApplicationDetail(row.id);
		const detail = res?.data || res; // 兼容后端返回结构
		showSettlementDialog.value = true;
		nextTick(() => {
			borrowForm.value = { ...(detail || {}), mode: 'settlement' };
		});
	} catch (error) {
		console.error('获取结算详情失败:', error);
		ElMessage.error('获取结算详情失败');
	}
}

async function handleRenewDevice(e: CustomEvent) {
	const res: any = await api.GetApplicationDetail(e.detail.id);
		if(res.code==2000){
			showSettlementDialog.value = true;
			nextTick(() => {
				borrowForm.value = { ...res.data, mode: 'renew' };
			});
		}else{
			ElMessage.error('获取续借详情失败');
		}
}



let observer: MutationObserver | null = null;

function bindBorrowActionbarButton(): boolean {
	const fsActionbar = document.querySelector('.borrow-page .fs-actionbar');
	if (!fsActionbar) return false;

	function insertButton() {
		if (fsActionbar && !fsActionbar.querySelector('.my-create-btn')) {
			const button = document.createElement('button');
			button.className = 'el-button el-button--primary el-button--default my-create-btn';
			button.innerHTML = '创建借用单';
			button.onclick = () => {
				showBorrowTypeDialog.value = true;
			};
			fsActionbar.append(button);
		}
	}

	insertButton();
	if (observer) {
		observer.disconnect();
		observer = null;
	}
	observer = new MutationObserver((_m, obs) => {
		insertButton();
		obs.disconnect();
	});
	observer.observe(fsActionbar, { childList: true });
	return true;
}

onMounted(() => {
	window.addEventListener('borrow-view', handleView);
	window.addEventListener('borrow-edit', handleEdit);
	window.addEventListener('borrow-remove', handleRemove);
	window.addEventListener('borrow-collect', handleCollect);
	window.addEventListener('borrow-return', handleReturn);
	window.addEventListener('borrow-settlement', handleSettlement);
	window.addEventListener('renew-device', handleRenewDevice);

	/* 必须执行：此前若未找到 .fs-actionbar 会提前 return，导致从未 doSearch，URL 带参也不生效 */
	nextTick(() => {
		applyRouteSearchToCrud();
	});

	if (!bindBorrowActionbarButton()) {
		nextTick(() => {
			if (!bindBorrowActionbarButton()) {
				window.setTimeout(() => bindBorrowActionbarButton(), 100);
			}
		});
	}
});

/** 同页仅 query 变化时（如 ?status=）；勿 watch 全局 fullPath，keep-alive 下会误触发 */
onBeforeRouteUpdate((to) => {
	nextTick(() => {
		crudExpose.doSearch({
			form: buildBorrowListSearchFormFromRoute(to.query),
		});
	});
});

onActivated(() => {
	if (skipNextActivatedBorrowSearch.value) {
		skipNextActivatedBorrowSearch.value = false;
		return;
	}
	crudExpose.doSearch({
		form: buildBorrowListSearchFormFromRoute(route.query),
	});
});
onBeforeUnmount(() => {
	if (observer) {
		observer.disconnect();
		observer = null;
	}
	// window.removeEventListener('borrow-add', () => {
	// 	showBorrowTypeDialog.value = false
	// });
	window.removeEventListener('borrow-view', handleView);
	window.removeEventListener('borrow-edit', handleEdit);
	window.removeEventListener('borrow-remove', handleRemove);
	window.removeEventListener('borrow-collect', handleCollect);
	window.removeEventListener('borrow-return', handleReturn);
	window.removeEventListener('borrow-settlement', handleSettlement);
	window.removeEventListener('renew-device', handleRenewDevice);
});

</script>
<style lang="scss" scoped></style>
