<script setup>

import "@/lib/array.js"
import useUtils from "@/utils/utils.js"
import {inject, ref} from "vue"
import HTTPRequestCondsView from "@/components/server/HTTPRequestCondsView.vue";
import HTTPRequestCondView from "@/components/server/HTTPRequestCondView.vue";
import GreyLabel from "@/components/common/GreyLabel.vue";
import TButton from "@/components/ui/TButton.vue";
import ListTable from "@/components/common/ListTable.vue";
import Column from "primevue/column";
import NotFoundInfo from "@/components/common/NotFoundInfo.vue";

const utils = useUtils()

const Tea = inject("$Tea")

const props = defineProps(["v-cache-refs", "v-cache-config", "v-cache-policy-id", "v-web-id", "v-max-bytes"])

const cacheRefs = ref({})

const {refs, id} = (function () {
	let refs = props.vCacheRefs
	if (refs == null) {
		refs = []
	}

	let maxBytes = props.vMaxBytes

	let id = 0
	refs.forEach(function (ref) {
		// preset variables
		id++
		ref.id = id
		ref.visible = true

		// check max size
		if (ref.maxSize != null && maxBytes != null && maxBytes.count > 0 && utils.compareSizeCapacity(ref.maxSize, maxBytes) > 0) {
			ref.overMaxSize = maxBytes
		}
	})
	return {
		refs: ref(refs),
		id: ref(id)
	}
})()

const addRef = function (isReverse) {
	window.UPDATING_CACHE_REF = null

	let height = window.innerHeight
	if (height > 600) {
		height = 540
	}
	utils.popup("/servers/server/settings/cache/createPopup?isReverse=" + (isReverse ? 1 : 0), {
		height: height + "px",
		callback: function (resp) {
			let newRef = resp.data.cacheRef
			if (newRef.conds == null) {
				return
			}

			id.value++
			newRef.id = id.value

			if (newRef.isReverse) {
				let newRefs = []
				let isAdded = false
				refs.value.forEach(function (v) {
					if (!v.isReverse && !isAdded) {
						newRefs.push(newRef)
						isAdded = true
					}
					newRefs.push(v)
				})
				if (!isAdded) {
					newRefs.push(newRef)
				}

				updateRefs(newRefs)
			} else {
				refs.value.push(newRef)
			}

			// move to bottom
			var afterChangeCallback = function () {
				setTimeout(function () {
					let rightBox = document.querySelector(".right-box")
					if (rightBox != null) {
						rightBox.scrollTo(0, isReverse ? 0 : 100000)
					}
				}, 100)
			}

			change(afterChangeCallback)
		}
	})
}

const updateRef = function (cacheRef) {
	window.UPDATING_CACHE_REF = utils.clone(cacheRef)

	let height = window.innerHeight
	if (height > 500) {
		height = 500
	}

	utils.popup("/servers/server/settings/cache/createPopup", {
		height: height + "px",
		callback: function (resp) {
			let index = -1
			refs.value.$each((k, v) => {
				if (v.id == cacheRef.id) {
					index = k
				}
			})
			if (index < 0) {
				return
			}

			resp.data.cacheRef.id = refs.value[index].id
			refs.value[index] = resp.data.cacheRef
			change()

			cacheRefs.value[cacheRef.id].updateConds(resp.data.cacheRef.conds, resp.data.cacheRef.simpleCond)
			cacheRefs.value[cacheRef.id].notifyChange()
		}
	})
}

const disableRef = function (ref) {
	ref.isOn = false
	change()
}

const enableRef = function (ref) {
	ref.isOn = true
	change()
}

const removeRef = function (cacheRef) {
	utils.confirm("确定要删除此缓存设置吗？", function () {
		refs.value.$removeIf((_, v) => {
			return v.id == cacheRef.id
		})
		change()
	})
}

const updateRefs = function (newRefs) {
	refs.value = newRefs
	if (props.vCacheConfig != null) {
		props.vCacheConfig.cacheRefs = newRefs
	}
}

const timeUnitName = function (unit) {
	switch (unit) {
		case "ms":
			return "毫秒"
		case "second":
			return "秒"
		case "minute":
			return "分钟"
		case "hour":
			return "小时"
		case "day":
			return "天"
		case "week":
			return "周 "
	}
	return unit
}

const change = function (callback) {
	// 自动保存
	if (props.vCachePolicyId != null && props.vCachePolicyId > 0) { // 缓存策略
		Tea.action("/servers/components/cache/updateRefs")
			.params({
				cachePolicyId: props.vCachePolicyId,
				refsJSON: JSON.stringify(refs.value)
			})
			.post()
	} else if (props.vWebId != null && props.vWebId > 0) { // Server Web or Group Web
		Tea.action("/servers/server/settings/cache/updateRefs")
			.params({
				webId: props.vWebId,
				refsJSON: JSON.stringify(refs.value)
			})
			.success(function (resp) {
				if (resp.data.isUpdated) {
					utils.successToast("保存成功", null, function () {
						if (typeof callback == "function") {
							callback()
						}
					})
				}
			})
			.post()
	}
}

const search = function (keyword) {
	if (typeof keyword != "string") {
		keyword = ""
	}

	refs.value.forEach(function (ref) {
		if (keyword.length == 0) {
			ref.visible = true
			return
		}
		ref.visible = false

		// simple cond
		if (ref.simpleCond != null && typeof ref.simpleCond.value == "string" && utils.match(ref.simpleCond.value, keyword)) {
			ref.visible = true
			return
		}

		// composed conds
		if (ref.conds == null || ref.conds.groups == null || ref.conds.groups.length == 0) {
			return
		}

		ref.conds.groups.forEach(function (group) {
			if (group.conds != null) {
				group.conds.forEach(function (cond) {
					if (typeof cond.value == "string" && utils.match(cond.value, keyword)) {
						ref.visible = true
					}
				})
			}
		})
	})
}

const sortTable = (ids) => {
	const m = {} // id => ref
	refs.value.forEach((r) => {
		m[r.id] = r
	})

	const newRefs = []
	ids.forEach(id => {
		newRefs.push(m[id])
	})

	refs.value = newRefs

	change()
}

defineExpose({
	addRef,
	search
})

</script>

<template>
	<div>
		<input type="hidden" name="refsJSON" :value="JSON.stringify(refs)"/>

		<div>
			<NotFoundInfo v-if="refs.length == 0">暂时还没有缓存条件。</NotFoundInfo>

			<div v-if="refs.length > 0">
				<ListTable :items="refs" @sort="sortTable" :row-class="ref => (ref.visible === false) ?  'hidden' : ''">
					<Column rowReorder headerStyle="width: 3em"></Column>
					<Column header="缓存条件">
						<!-- TODO 实现  :bodyClass="{'color-border': cacheRef.conds != null && cacheRef.conds.connector == 'and', disabled: !cacheRef.isOn}" :style="{'border-left':cacheRef.isReverse ? '1px #db2828 solid' : ''}" -->
						<template #body="{data: cacheRef}">
							<div :key="'conds:' + cacheRef.id">
								<HTTPRequestCondsView :v-conds="cacheRef.conds" :ref="el => { cacheRefs[cacheRef.id] = el }" :class="{disabled: !cacheRef.isOn}" v-if="cacheRef.conds != null && cacheRef.conds.groups != null" class="mb-2"></HTTPRequestCondsView>
								<HTTPRequestCondView :v-cond="cacheRef.simpleCond" :ref="el => { cacheRefs[cacheRef.id] = el }" v-if="cacheRef.simpleCond != null" class="mb-2" :isOn="cacheRef.isOn" :isReverse="cacheRef.isReverse"></HTTPRequestCondView>

								<div class="flex flex-wrap gap-1">
									<!-- 特殊参数 -->
									<GreyLabel v-if="cacheRef.key != null && cacheRef.key.indexOf('\${args}') < 0">忽略URI参数</GreyLabel>

									<GreyLabel v-if="cacheRef.minSize != null && cacheRef.minSize.count > 0">
										{{ cacheRef.minSize.count }}{{ cacheRef.minSize.unit }}
										<span v-if="cacheRef.maxSize != null && cacheRef.maxSize.count > 0">- {{ cacheRef.maxSize.count }}{{ cacheRef.maxSize.unit.toUpperCase() }}</span>
									</GreyLabel>
									<GreyLabel v-else-if="cacheRef.maxSize != null && cacheRef.maxSize.count > 0">0 - {{ cacheRef.maxSize.count }}{{ cacheRef.maxSize.unit.toUpperCase() }}</GreyLabel>

									<GreyLabel v-if="cacheRef.overMaxSize != null">
										<span class="red">系统限制{{ cacheRef.overMaxSize.count }}{{ cacheRef.overMaxSize.unit.toUpperCase() }}</span>
									</GreyLabel>

									<GreyLabel v-if="cacheRef.methods != null && cacheRef.methods.length > 0">{{ cacheRef.methods.join(", ") }}</GreyLabel>
									<GreyLabel v-if="cacheRef.expiresTime != null && cacheRef.expiresTime.isPrior && cacheRef.expiresTime.isOn">Expires</GreyLabel>
									<GreyLabel v-if="cacheRef.status != null && cacheRef.status.length > 0 && (cacheRef.status.length > 1 || cacheRef.status[0] != 200)">状态码：{{ cacheRef.status.map(function (v) {
										return v.toString()
									}).join(", ") }}
									</GreyLabel>
									<GreyLabel v-if="cacheRef.allowPartialContent">分片缓存</GreyLabel>
									<GreyLabel v-if="cacheRef.alwaysForwardRangeRequest">Range回源</GreyLabel>
									<GreyLabel v-if="cacheRef.enableIfNoneMatch">If-None-Match</GreyLabel>
									<GreyLabel v-if="cacheRef.enableIfModifiedSince">If-Modified-Since</GreyLabel>
									<GreyLabel v-if="cacheRef.enableReadingOriginAsync">支持异步</GreyLabel>
								</div>
							</div>
						</template>
					</Column>
					<Column header="缓存时间" headerStyle="width: 7em">
						<template #body="{data: cacheRef}">
							<div :key="'life:' + cacheRef.id">
								<span v-if="!cacheRef.isReverse">{{ cacheRef.life.count }} {{ timeUnitName(cacheRef.life.unit) }}</span>
								<span v-else class="red">不缓存</span>
							</div>
						</template>
					</Column>
					<Column header="操作" headerClass="three op">
						<template #body="{data: cacheRef}">
							<div :key="'op:' + cacheRef.id">
								<a href="" @click.prevent="updateRef(cacheRef)">修改</a> &nbsp;
								<a href="" v-if="cacheRef.isOn" @click.prevent="disableRef(cacheRef)">暂停</a><a href="" v-if="!cacheRef.isOn" @click.prevent="enableRef(cacheRef)"><span class="red">恢复</span></a> &nbsp;
								<a href="" @click.prevent="removeRef(cacheRef)">删除</a>
							</div>
						</template>
					</Column>
				</ListTable>
			</div>

			<p class="comment flex items-center" v-if="refs.length > 1">所有条件匹配顺序为从上到下，可以拖动左侧的<i class="icon pi pi-bars"></i>排序。网站设置的优先级比全局缓存策略设置的优先级要高。
			</p>

			<div class="mt-4 flex gap-2">
				<TButton outlined @click.prevent="addRef(false)" type="button"><i class="pi pi-pen-to-square"></i>添加缓存条件</TButton> &nbsp; &nbsp;
				<a href="" @click.prevent="addRef(true)" class="text-sm flex items-center gap-2" style="color: var(--p-text-muted-color)">添加不缓存条件</a>
			</div>
		</div>
	</div>
</template>

<style scoped>
</style>
