<script setup>
import {ref} from "vue";
import "@/lib/array.js"
import useUtils from "@/utils/utils.js";
import TInputText from "@/components/ui/TInputText.vue";
import TButton from "@/components/ui/TButton.vue";
import TDivider from "@/components/ui/TDivider.vue";
import CodeLabel from "@/components/common/CodeLabel.vue";
import ComboBox from "@/components/common/ComboBox.vue";
import TOption from "@/components/ui/TOption.vue";
import TSelect from "@/components/ui/TSelect.vue";
import TCheckboxBinary from "@/components/ui/TCheckboxBinary.vue";
import TLabel from "@/components/ui/TLabel.vue";
import TTextarea from "@/components/ui/TTextarea.vue";
import DefinitionTable from "@/components/common/DefinitionTable.vue";

const utils = useUtils()

const props = defineProps(["v-ranges"])
const {
	ranges,
	isAdding,
	isAddingBatch,
	rangeType,
	isReverse,
	ipRangeFrom,
	ipRangeTo,
	batchIPRange,
	ipCIDR,
	batchIPCIDR,
	regions,
	regionType,
	regionConnector
} = (function () {
	let ranges = props.vRanges
	if (ranges == null) {
		ranges = []
	}
	return {
		ranges: ref(ranges),
		isAdding: ref(false),
		isAddingBatch: ref(false),

		// 类型
		rangeType: ref("ipRange"),
		isReverse: ref(false),

		// IP范围
		ipRangeFrom: ref(""),
		ipRangeTo: ref(""),

		batchIPRange: ref(""),

		// CIDR
		ipCIDR: ref(""),
		batchIPCIDR: ref(""),

		// region
		regions: ref([]),
		regionType: ref("country"),
		regionConnector: ref("OR")
	}
})()

const ipCIDRRef = ref()
const ipRangeFromRef = ref()
const ipRangeToRef = ref()
const batchIPRangeRef = ref()
const batchIPCIDRRef = ref()
const regionCountryComboBoxRef = ref()
const regionCityComboBoxRef = ref()
const regionProvinceComboBoxRef = ref()
const regionProviderComboBoxRef = ref()

const addIPRange = function () {
	isAdding.value = true
	setTimeout(function () {
		ipRangeFromRef.value.focus()
	}, 100)
}

const addCIDR = function () {
	isAdding.value = true
	setTimeout(function () {
		ipCIDRRef.value.focus()
	}, 100)
}

const addRegions = function () {
	isAdding.value = true
}

const addRegion = function (newRegionType) {
	regionType.value = newRegionType
}

const remove = function (index) {
	ranges.value.$remove(index)
}

const cancelIPRange = function () {
	isAdding.value = false
	ipRangeFrom.value = ""
	ipRangeTo.value = ""
	isReverse.value = false
}

const cancelIPCIDR = function () {
	isAdding.value = false
	ipCIDR.value = ""
	isReverse.value = false
}

const cancelRegions = function () {
	isAdding.value = false
	regions.value = []
	regionType.value = "country"
	regionConnector.value = "OR"
	isReverse.value = false
}

const confirmIPRange = function () {
	// 校验IP
	ipRangeFrom.value = ipRangeFrom.value.trim()
	if (!validateIP(ipRangeFrom.value)) {
		utils.warn("开始IP填写错误", function () {
			ipRangeFromRef.value.focus()
		})
		return
	}

	ipRangeTo.value = ipRangeTo.value.trim()
	if (!validateIP(ipRangeTo.value)) {
		utils.warn("结束IP填写错误", function () {
			ipRangeToRef.value.focus()
		})
		return
	}

	ranges.value.push({
		type: "ipRange",
		params: {
			ipFrom: ipRangeFrom.value,
			ipTo: ipRangeTo.value,
			isReverse: isReverse.value
		}
	})
	cancelIPRange()
}

const confirmIPCIDR = function () {
	if (ipCIDR.value.length == 0) {
		utils.warn("请填写CIDR", function () {
			ipCIDRRef.value.focus()
		})
		return
	}
	if (!validateCIDR(ipCIDR.value)) {
		utils.warn("请输入正确的CIDR", function () {
			ipCIDRRef.value.focus()
		})
		return
	}

	ranges.value.push({
		type: "cidr",
		params: {
			cidr: ipCIDR.value,
			isReverse: isReverse.value
		}
	})
	cancelIPCIDR()
}

const confirmRegions = function () {
	if (regions.value.length == 0) {
		cancelRegions()
		return
	}
	ranges.value.push({
		type: "region",
		connector: regionConnector.value,
		params: {
			regions: regions.value,
			isReverse: isReverse.value
		}
	})
	cancelRegions()
}

const addBatchIPRange = function () {
	isAddingBatch.value = true
	setTimeout(function () {
		batchIPRangeRef.value.focus()
	}, 100)
}

const addBatchCIDR = function () {
	isAddingBatch.value = true
	setTimeout(function () {
		batchIPCIDRRef.value.focus()
	}, 100)
}

const cancelBatchIPRange = function () {
	isAddingBatch.value = false
	batchIPRange.value = ""
	isReverse.value = false
}

const cancelBatchIPCIDR = function () {
	isAddingBatch.value = false
	batchIPCIDR.value = ""
	isReverse.value = false
}

const confirmBatchIPRange = function () {
	let rangesText = batchIPRange.value
	if (rangesText.length == 0) {
		utils.warn("请填写要加入的IP范围", function () {
			batchIPRangeRef.value.focus()
		})
		return
	}

	let validRanges = []
	let invalidLine = ""
	rangesText.split("\n").forEach(function (line) {
		line = line.trim()
		if (line.length == 0) {
			return
		}
		line = line.replace("，", ",")
		let pieces = line.split(",")
		if (pieces.length != 2) {
			invalidLine = line
			return
		}
		let ipFrom = pieces[0].trim()
		let ipTo = pieces[1].trim()
		if (!validateIP(ipFrom) || !validateIP(ipTo)) {
			invalidLine = line
			return
		}
		validRanges.push({
			type: "ipRange",
			params: {
				ipFrom: ipFrom,
				ipTo: ipTo,
				isReverse: isReverse.value
			}
		})
	})
	if (invalidLine.length > 0) {
		utils.warn("'" + invalidLine + "'格式错误", function () {
			batchIPRangeRef.value.focus()
		})
		return
	}
	validRanges.forEach(function (v) {
		ranges.value.push(v)
	})
	cancelBatchIPRange()
}

const confirmBatchIPCIDR = function () {
	let rangesText = batchIPCIDR.value
	if (rangesText.length == 0) {
		utils.warn("请填写要加入的CIDR", function () {
			batchIPCIDRRef.value.focus()
		})
		return
	}

	let validRanges = []
	let invalidLine = ""
	rangesText.split("\n").forEach(function (line) {
		let cidr = line.trim()
		if (cidr.length == 0) {
			return
		}
		if (!validateCIDR(cidr)) {
			invalidLine = line
			return
		}
		validRanges.push({
			type: "cidr",
			params: {
				cidr: cidr,
				isReverse: isReverse.value
			}
		})
	})
	if (invalidLine.length > 0) {
		utils.warn("'" + invalidLine + "'格式错误", function () {
			batchIPCIDRRef.focus()
		})
		return
	}
	validRanges.forEach(function (v) {
		ranges.value.push(v)
	})
	cancelBatchIPCIDR()
}

const selectRegionCountry = function (country) {
	if (country == null) {
		return
	}
	regions.value.push({
		type: "country",
		id: country.id,
		name: country.name
	})
	regionCountryComboBoxRef.value.clear()
}

const selectRegionProvince = function (province) {
	if (province == null) {
		return
	}
	regions.value.push({
		type: "province",
		id: province.id,
		name: province.name
	})
	regionProvinceComboBoxRef.value.clear()
}

const selectRegionCity = function (city) {
	if (city == null) {
		return
	}
	regions.value.push({
		type: "city",
		id: city.id,
		name: city.name
	})
	regionCityComboBoxRef.value.clear()
}

const selectRegionProvider = function (provider) {
	if (provider == null) {
		return
	}
	regions.value.push({
		type: "provider",
		id: provider.id,
		name: provider.name
	})
	regionProviderComboBoxRef.value.clear()
}

const removeRegion = function (index) {
	regions.value.$remove(index)
}

const validateIP = function (ip) {
	if (ip.length == 0) {
		return
	}

	// IPv6
	if (ip.indexOf(":") >= 0) {
		let pieces = ip.split(":")
		if (pieces.length > 8) {
			return false
		}
		let isOk = true
		pieces.forEach(function (piece) {
			if (!/^[\da-fA-F]{0,4}$/.test(piece)) {
				isOk = false
			}
		})

		return isOk
	}

	if (!ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/)) {
		return false
	}
	let pieces = ip.split(".")
	let isOk = true
	pieces.forEach(function (v) {
		let v1 = parseInt(v)
		if (v1 > 255) {
			isOk = false
		}
	})
	return isOk
}

const validateCIDR = function (cidr) {
	let pieces = cidr.split("/")
	if (pieces.length != 2) {
		return false
	}
	let ip = pieces[0]
	if (!validateIP(ip)) {
		return false
	}
	let mask = pieces[1]
	if (!/^\d{1,3}$/.test(mask)) {
		return false
	}
	mask = parseInt(mask, 10)
	if (cidr.indexOf(":") >= 0) { // IPv6
		return mask <= 128
	}
	return mask <= 32
}

const updateRangeType = function (newRangeType) {
	rangeType.value = newRangeType
}

/**
 * expose
 */
defineExpose({
	updateRangeType
})

</script>

<template>
	<div>
		<input type="hidden" name="rangesJSON" :value="JSON.stringify(ranges)"/>
		<div v-if="ranges.length > 0" class="label-group">
			<TLabel outlined="" v-for="(range, index) in ranges" >
				<span class="red" v-if="range.params.isReverse">[排除]</span>
				<span v-if="range.type == 'ipRange'">IP范围：</span>
				<span v-if="range.type == 'cidr'">CIDR：</span>
				<span v-if="range.type == 'region'"></span>
				<span v-if="range.type == 'ipRange'">{{ range.params.ipFrom }} - {{ range.params.ipTo }}</span>
				<span v-if="range.type == 'cidr'">{{ range.params.cidr }}</span>
				<span v-if="range.type == 'region'">
				<span v-for="(region, index) in range.params.regions">
					<span v-if="region.type == 'country'">国家/地区</span>
					<span v-if="region.type == 'province'">省份</span>
					<span v-if="region.type == 'city'">城市</span>
					<span v-if="region.type == 'provider'">ISP</span>
					：{{ region.name }}
					<span v-if="index < range.params.regions.length - 1" class="grey">
						&nbsp;
						<span v-if="range.connector == 'OR' || range.connector == '' || range.connector == null">或</span>
						<span v-if="range.connector == 'AND'">且</span>
						&nbsp;
					</span>
				</span>
			</span>
				&nbsp; <a href="" title="删除" @click.prevent="remove(index)"><i class="pi pi-remove small"></i></a>
			</TLabel>
			<TDivider></TDivider>
		</div>

		<!-- IP范围 -->
		<div v-if="rangeType == 'ipRange'">
			<!-- 添加单个IP范围 -->
			<div style="margin-bottom: 1em" v-show="isAdding">
				<DefinitionTable>
					<tbody>
					<tr>
						<td class="title">开始IP *</td>
						<td>
							<TInputText type="text" placeholder="开始IP" maxlength="40" size="40" style="width: 15em" v-model="ipRangeFrom" ref="ipRangeFromRef" @keyup.enter="confirmIPRange" @keypress.enter.prevent="1" class="font-normal"/>
						</td>
					</tr>
					<tr>
						<td>结束IP *</td>
						<td>
							<TInputText type="text" placeholder="结束IP" maxlength="40" size="40" style="width: 15em" v-model="ipRangeTo" ref="ipRangeToRef" @keyup.enter="confirmIPRange" @keypress.enter.prevent="1" class="font-normal"/>
						</td>
					</tr>
					<tr>
						<td>排除</td>
						<td>
							<TCheckboxBinary v-model="isReverse"></TCheckboxBinary>
							<p class="comment">选中后表示线路中排除当前条件。</p>
						</td>
					</tr>
					</tbody>
				</DefinitionTable>
				<TButton secondary="" size="small" type="button" @click.prevent="confirmIPRange">确定</TButton> &nbsp;
				<a href="" @click.prevent="cancelIPRange" title="取消"><i class="pi pi-remove small"></i></a>
			</div>

			<!-- 添加多个IP范围 -->
			<div style="margin-bottom: 1em" v-show="isAddingBatch">
				<DefinitionTable>
					<tbody>
					<tr>
						<td class="title">IP范围列表 *</td>
						<td>
							<TTextarea rows="5" ref="batchIPRangeRef" v-model="batchIPRange" class="w-full font-normal"></TTextarea>
							<p class="comment">每行一条，格式为
								<CodeLabel>开始IP,结束IP</CodeLabel>
								，比如
								<CodeLabel>192.168.1.100,192.168.1.200</CodeLabel>
								。
							</p>
						</td>
					</tr>
					<tr>
						<td>排除</td>
						<td>
							<TCheckboxBinary v-model="isReverse"></TCheckboxBinary>
							<p class="comment">选中后表示线路中排除当前条件。</p>
						</td>
					</tr>
					</tbody>
				</DefinitionTable>
				<TButton secondary="" size="small" type="button" @click.prevent="confirmBatchIPRange">确定</TButton> &nbsp;
				<a href="" @click.prevent="cancelBatchIPRange" title="取消"><i class="pi pi-remove small"></i></a>
			</div>

			<div v-if="!isAdding && !isAddingBatch">
				<TButton secondary="" size="small" type="button" @click.prevent="addIPRange">添加单个IP范围</TButton> &nbsp;
				<TButton secondary="" size="small" type="button" @click.prevent="addBatchIPRange">批量添加IP范围</TButton>
			</div>
		</div>

		<!-- CIDR -->
		<div v-if="rangeType == 'cidr'">
			<!-- 添加单个IP范围 -->
			<div style="margin-bottom: 1em" v-show="isAdding">
				<DefinitionTable>
					<tbody>
					<tr>
						<td class="title">CIDR *</td>
						<td>
							<TInputText type="text" placeholder="IP/MASK" maxlength="40" size="40" style="width: 15em" v-model="ipCIDR" ref="ipCIDRRef" @keyup.enter="confirmIPCIDR" @keypress.enter.prevent="1" class="font-normal"/>
							<p class="comment">类似于
								<CodeLabel>192.168.2.1/24</CodeLabel>
								。
							</p>
						</td>
					</tr>
					<tr>
						<td>排除</td>
						<td>
							<TCheckboxBinary v-model="isReverse"></TCheckboxBinary>
							<p class="comment">选中后表示线路中排除当前条件。</p>
						</td>
					</tr>
					</tbody>
				</DefinitionTable>
				<TButton secondary="" size="small" type="button" @click.prevent="confirmIPCIDR">确定</TButton> &nbsp;
				<a href="" @click.prevent="cancelIPCIDR" title="取消"><i class="pi pi-remove small"></i></a>
			</div>

			<!-- 添加多个IP范围 -->
			<div style="margin-bottom: 1em" v-show="isAddingBatch">
				<DefinitionTable>
					<tbody>
					<tr>
						<td class="title">IP范围列表 *</td>
						<td>
							<TTextarea rows="5" ref="batchIPCIDRRef" v-model="batchIPCIDR" class="w-full font-normal"></TTextarea>
							<p class="comment">每行一条，格式为
								<CodeLabel>IP/MASK</CodeLabel>
								，比如
								<CodeLabel>192.168.2.1/24</CodeLabel>
								。
							</p>
						</td>
					</tr>
					<tr>
						<td>排除</td>
						<td>
							<TCheckboxBinary v-model="isReverse"></TCheckboxBinary>
							<p class="comment">选中后表示线路中排除当前条件。</p>
						</td>
					</tr>
					</tbody>
				</DefinitionTable>
				<TButton secondary="" size="small" type="button" @click.prevent="confirmBatchIPCIDR">确定</TButton> &nbsp;
				<a href="" @click.prevent="cancelBatchIPCIDR" title="取消"><i class="pi pi-remove small"></i></a>
			</div>

			<div v-if="!isAdding && !isAddingBatch">
				<TButton secondary="" size="small" type="button" @click.prevent="addCIDR">添加单个CIDR</TButton> &nbsp;
				<TButton secondary="" size="small" type="button" @click.prevent="addBatchCIDR">批量添加CIDR</TButton>
			</div>
		</div>

		<!-- 区域 -->
		<div v-if="rangeType == 'region'">
			<!-- 添加区域 -->
			<div v-if="isAdding">
				<DefinitionTable>
					<tbody>
					<tr>
						<td>已添加</td>
						<td>
							<div class="label-group">
								<span v-for="(region, index) in regions">
									<TLabel outlined="">
										<span v-if="region.type == 'country'">国家/地区</span>
										<span v-if="region.type == 'province'">省份</span>
										<span v-if="region.type == 'city'">城市</span>
										<span v-if="region.type == 'provider'">ISP</span>
										：{{ region.name }} <a href="" title="删除" @click.prevent="removeRegion(index)"><i class="pi pi-remove small"></i></a>
									</TLabel>
									<span v-if="index < regions.length - 1" class="grey">
										&nbsp;
										<span v-if="regionConnector == 'OR' || regionConnector == ''">或</span>
										<span v-if="regionConnector == 'AND'">且</span>
										&nbsp;
									</span>
								</span>
							</div>
						</td>
					</tr>
					<tr>
						<td class="title">添加新<span v-if="regionType == 'country'">国家/地区</span><span v-if="regionType == 'province'">省份</span><span v-if="regionType == 'city'">城市</span><span v-if="regionType == 'provider'">ISP</span>

							*
						</td>
						<td>
							<!-- region country name -->
							<div v-if="regionType == 'country'">
								<ComboBox title="" width="14em" data-url="/ui/countryOptions" data-key="countries" placeholder="点这里选择国家/地区" @change="selectRegionCountry" ref="regionCountryComboBoxRef" key="combo-box-country"></ComboBox>
							</div>

							<!-- region province name -->
							<div v-if="regionType == 'province'">
								<ComboBox title="" data-url="/ui/provinceOptions" data-key="provinces" placeholder="点这里选择省份" @change="selectRegionProvince" ref="regionProvinceComboBoxRef" key="combo-box-province"></ComboBox>
							</div>

							<!-- region city name -->
							<div v-if="regionType == 'city'">
								<ComboBox title="" data-url="/ui/cityOptions" data-key="cities" placeholder="点这里选择城市" @change="selectRegionCity" ref="regionCityComboBoxRef" key="combo-box-city"></ComboBox>
							</div>

							<!-- ISP Name -->
							<div v-if="regionType == 'provider'">
								<ComboBox title="" data-url="/ui/providerOptions" data-key="providers" placeholder="点这里选择ISP" @change="selectRegionProvider" ref="regionProviderComboBoxRef" key="combo-box-isp"></ComboBox>
							</div>

							<div style="margin-top: 1em">
								<TButton secondary="" size="small" :class="{blue: regionType == 'country'}" type="button" @click.prevent="addRegion('country')">添加国家/地区</TButton> &nbsp;
								<TButton secondary="" size="small" :class="{blue: regionType == 'province'}" type="button" @click.prevent="addRegion('province')">添加省份</TButton> &nbsp;
								<TButton secondary="" size="small" :class="{blue: regionType == 'city'}" type="button" @click.prevent="addRegion('city')">添加城市</TButton> &nbsp;
								<TButton secondary="" size="small" :class="{blue: regionType == 'provider'}" type="button" @click.prevent="addRegion('provider')">ISP</TButton> &nbsp;
							</div>
						</td>
					</tr>
					<tr>
						<td>区域之间关系</td>
						<td>
							<TSelect v-model="regionConnector">
								<TOption value="OR">或</TOption>
								<TOption value="AND">且</TOption>
							</TSelect>
							<p class="comment" v-if="regionConnector == 'OR'">匹配所选任一区域即认为匹配成功。</p>
							<p class="comment" v-if="regionConnector == 'AND'">匹配所有所选区域才认为匹配成功。</p>
						</td>
					</tr>
					<tr>
						<td>排除</td>
						<td>
							<TCheckboxBinary v-model="isReverse"></TCheckboxBinary>
							<p class="comment">选中后表示线路中排除当前条件。</p>
						</td>
					</tr>
					</tbody>
				</DefinitionTable>
				<TButton secondary="" size="small" type="button" @click.prevent="confirmRegions">确定</TButton> &nbsp;
				<a href="" @click.prevent="cancelRegions" title="取消"><i class="pi pi-remove small"></i></a>
			</div>
			<div v-if="!isAdding && !isAddingBatch">
				<TButton secondary="" size="small" type="button" @click.prevent="addRegions">添加区域</TButton> &nbsp;
			</div>
		</div>
	</div>
</template>

<style scoped lang="postcss">

</style>