<template>
	<cl-crud ref="Crud">
		<cl-row>
			<cl-refresh-btn />
			<cl-add-btn />
			<cl-multi-delete-btn />
			<el-button :icon="unmaskAll ? 'Hide' : 'View'" @click="unmaskAll = !unmaskAll">
				{{ unmaskAll ? t('隐藏全部密码') : t('显示全部密码') }}
			</el-button>
			<cl-flex1 />
			<cl-search-key :placeholder="t('搜索名称、IP、城市')" />
		</cl-row>

		<cl-row>
			<cl-table ref="Table">
				<!-- IP:端口号 + 出口 IP -->
				<template #column-ipPort="{ scope }">
					<div class="ip-cell">
						<div class="ip-main">{{ scope.row.host }}:{{ scope.row.port }}</div>
						<div v-if="scope.row.exitIp" class="ip-exit">出: {{ scope.row.exitIp }}</div>
					</div>
				</template>

				<!-- 账号 | 密码 -->
				<template #column-credential="{ scope }">
					<div class="cred-cell">
						<span>{{ scope.row.username || '-' }}</span>
						<span class="cred-sep">|</span>
						<span>{{ isUnmasked(scope.row.id) ? scope.row.password : maskPwd(scope.row.password) }}</span>
						<el-icon class="cred-toggle" @click.stop="toggleUnmask(scope.row.id)">
							<component :is="isUnmasked(scope.row.id) ? 'Hide' : 'View'" />
						</el-icon>
					</div>
				</template>

				<!-- 剩余时长 -->
				<template #column-remainDays="{ scope }">
					<el-tag v-if="scope.row.expiresAt" :type="remainTagType(scope.row.expiresAt)" size="small">
						{{ remainText(scope.row.expiresAt) }}
					</el-tag>
					<span v-else class="text-gray">-</span>
				</template>

				<!-- 状态 -->
				<template #column-status="{ scope }">
					<el-tag :type="statusTagType(scope.row.status)" size="small">
						{{ statusText(scope.row.status) }}
					</el-tag>
				</template>
			</cl-table>
		</cl-row>

		<cl-row>
			<cl-flex1 />
			<cl-pagination />
		</cl-row>

		<cl-upsert ref="Upsert" />
	</cl-crud>
</template>

<script lang="ts" setup>
defineOptions({ name: 'geo-proxies' });

import { ref, reactive } from 'vue';
import { useCrud, useTable, useUpsert } from '@cool-vue/crud';
import { useCool } from '/@/cool';
import { useI18n } from 'vue-i18n';
import { ElMessage, ElMessageBox } from 'element-plus';

const { service } = useCool();
const { t } = useI18n();

// 密码遮罩状态
const unmaskAll = ref(false);
const unmaskRows = reactive<Record<number, boolean>>({});

function isUnmasked(id: number): boolean {
	return unmaskAll.value || !!unmaskRows[id];
}
function toggleUnmask(id: number) {
	unmaskRows[id] = !unmaskRows[id];
}
function maskPwd(pwd: string | undefined | null): string {
	if (!pwd) return '-';
	return '••••••';
}

// 剩余天数
function remainDays(expiresAt: string | Date): number {
	const ms = new Date(expiresAt).getTime() - Date.now();
	return Math.ceil(ms / 86400000);
}
function remainText(expiresAt: string | Date): string {
	const d = remainDays(expiresAt);
	if (d <= 0) return t('已过期');
	return d + t('天');
}
function remainTagType(expiresAt: string | Date): 'success' | 'warning' | 'danger' {
	const d = remainDays(expiresAt);
	if (d <= 0) return 'danger';
	if (d <= 7) return 'warning';
	return 'success';
}

// 状态
function statusText(s: string): string {
	const map: Record<string, string> = {
		active: t('正常'),
		expired: t('已过期'),
		error: t('异常'),
		unbound: t('未绑定'),
	};
	return map[s] || s || '-';
}
function statusTagType(s: string): 'success' | 'danger' | 'warning' | 'info' {
	if (s === 'active') return 'success';
	if (s === 'expired' || s === 'error') return 'danger';
	if (s === 'unbound') return 'warning';
	return 'info';
}

// 编辑表单
const Upsert = useUpsert({
	dialog: { width: '600px' },
	props: { labelWidth: '100px' },
	items: [
		{ label: t('名称'), prop: 'name', required: true, component: { name: 'el-input' } },
		{
			label: t('供应商'),
			prop: 'provider',
			required: true,
			value: 'local',
			component: {
				name: 'el-select',
				options: [
					{ label: 'Local', value: 'local' },
					{ label: '天启', value: 'tianqi' },
				],
			},
		},
		{
			label: t('模式'),
			prop: 'mode',
			required: true,
			value: 'local',
			component: {
				name: 'el-select',
				options: [
					{ label: '本地', value: 'local' },
					{ label: '第三方', value: 'third_party' },
				],
			},
		},
		{
			label: t('协议'),
			prop: 'protocol',
			value: 'http',
			component: {
				name: 'el-select',
				options: [
					{ label: 'HTTP', value: 'http' },
					{ label: 'SOCKS5', value: 'socks5' },
				],
			},
		},
		{ label: t('主机'), prop: 'host', component: { name: 'el-input', props: { placeholder: '210.51.27.112' } } },
		{
			label: t('端口'),
			prop: 'port',
			component: { name: 'el-input-number', props: { min: 1, max: 65535, controlsPosition: 'right' } },
		},
		{ label: t('用户名'), prop: 'username', component: { name: 'el-input' } },
		{ label: t('密码'), prop: 'password', component: { name: 'el-input', props: { showPassword: true } } },
		{ label: t('出口IP'), prop: 'exitIp', component: { name: 'el-input', props: { placeholder: '可选，测试后自动填' } } },
		{ label: t('开通城市'), prop: 'city', component: { name: 'el-input', props: { placeholder: '上海' } } },
		{ label: t('套餐ID'), prop: 'packageId', component: { name: 'el-input' } },
		{ label: t('地区'), prop: 'region', component: { name: 'el-input' } },
		{ label: t('ISP'), prop: 'isp', component: { name: 'el-input' } },
		{
			label: t('过期时间'),
			prop: 'expiresAt',
			component: {
				name: 'el-date-picker',
				props: { type: 'datetime', valueFormat: 'YYYY-MM-DD HH:mm:ss', placeholder: '选择过期时间' },
			},
		},
	],
});

// 表格
const Table = useTable({
	contextMenu: ['refresh', 'edit', 'delete'],
	columns: [
		{ type: 'selection' },
		{ label: 'ID', prop: 'id', width: 60 },
		{ label: t('名称'), prop: 'name', minWidth: 120, showOverflowTooltip: true },
		{ label: t('IP地址:端口号'), prop: 'ipPort', minWidth: 180 },
		{ label: t('账号|密码'), prop: 'credential', minWidth: 220 },
		{ label: t('开通城市'), prop: 'city', minWidth: 100 },
		{ label: t('剩余时长'), prop: 'remainDays', minWidth: 110 },
		{ label: t('所属套餐'), prop: 'packageId', minWidth: 180, showOverflowTooltip: true },
		{ label: t('协议'), prop: 'protocol', minWidth: 80 },
		{ label: t('状态'), prop: 'status', minWidth: 100 },
		{ label: t('延迟(ms)'), prop: 'latencyMs', minWidth: 90 },
		{ label: t('最后检测'), prop: 'lastCheckAt', minWidth: 160, sortable: 'custom' },
		{
			type: 'op',
			width: 200,
			buttons: [
				{
					label: t('测试'),
					type: 'primary',
					onClick({ scope }) {
						testProxy(scope.row.id);
					},
				},
				'edit',
				'delete',
			],
		},
	],
});

// CRUD
const Crud = useCrud(
	{ service: service.geo.proxy_ip },
	(app) => {
		app.refresh();
	}
);

// 测试 IP（入站+出站）
async function testProxy(id: number) {
	const loading = ElMessage({ message: t('正在测试 IP...'), type: 'info', duration: 0 });
	try {
		const r: any = await service.request({
			url: '/admin/geo/proxy_ip/test',
			method: 'POST',
			data: { id },
		});
		loading.close();
		if (r?.ok) {
			const lines = [
				`✅ ${t('代理可用')}`,
				`${t('延迟')}: ${r.latencyMs}ms`,
				`${t('出口IP')}: ${r.exitIp}`,
				`${t('入口IP')}: ${r.expectedIp}`,
				r.ipMatch === false
					? `⚠️ ${t('出口IP与入口IP不一致（住宅代理常见，正常）')}`
					: `✓ ${t('出口IP匹配')}`,
			];
			ElMessageBox.alert(lines.join('\n'), t('测试结果'), { confirmButtonText: t('确定'), customStyle: { whiteSpace: 'pre-line' } });
		} else {
			ElMessageBox.alert(`❌ ${t('代理不可用')}\n${t('延迟')}: ${r?.latencyMs ?? '-'}ms\n${t('错误')}: ${r?.error || t('未知')}`, t('测试结果'), {
				type: 'error',
				confirmButtonText: t('确定'),
				customStyle: { whiteSpace: 'pre-line' },
			});
		}
		Crud.value?.refresh();
	} catch (e: any) {
		loading.close();
		ElMessage.error(e?.message || t('测试失败'));
	}
}
</script>

<style lang="scss" scoped>
.ip-cell {
	display: flex;
	flex-direction: column;
	line-height: 1.4;
	.ip-main {
		font-weight: 500;
	}
	.ip-exit {
		font-size: 12px;
		color: #909399;
	}
}

.cred-cell {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	font-family: Consolas, Menlo, monospace;
	.cred-sep {
		color: #c0c4cc;
	}
	.cred-toggle {
		cursor: pointer;
		color: #409eff;
		margin-left: 4px;
		&:hover {
			color: #66b1ff;
		}
	}
}

.text-gray {
	color: #909399;
}
</style>
