<template>
	<Dialog v-if="show" :options="{ title, position: 'top' }" v-model="show">
		<template v-slot:body-content>
			<div class="flex flex-col gap-4">
				<p class="text-base text-gray-600">
					您可以通过输入补丁URL或选择补丁文件来选择应用程序补丁。
				</p>
				<div class="flex flex-col gap-2">
					<FormControl
						v-if="!app"
						class="w-full"
						v-model="applyToApp"
						label="选择应用"
						placeholder="选择要打补丁的应用"
						type="select"
						variant="outline"
						:options="$resources.apps.data"
					/>

					<!-- 补丁选择器（URL或文件） -->
					<div class="flex w-full items-end gap-1">
						<FormControl
							v-if="!patch"
							class="w-full"
							label="补丁URL"
							type="data"
							v-model="patchURL"
							variant="outline"
							placeholder="输入补丁URL"
						/>
						<FormControl
							v-else
							class="w-full"
							label="补丁文件名"
							type="data"
							variant="outline"
							v-model="patchFileName"
							placeholder="设置补丁文件名"
						/>

						<!-- 文件选择器 -->
						<input
							ref="fileSelector"
							type="file"
							:accept="['text/x-patch', 'text/x-diff', 'application/x-patch']"
							class="hidden"
							@change="onPatchFileSelect"
						/>
						<Button
							@click="$refs.fileSelector.click()"
							title="选择补丁文件"
						>
							<FeatherIcon name="file-text" class="h-5 w-5 text-gray-600" />
						</Button>

						<!-- 清除补丁文件 -->
						<Button @click="clear" v-if="patch" title="清除补丁文件">
							<FeatherIcon name="x" class="h-5 w-5 text-gray-600" />
						</Button>
					</div>
				</div>
				<ErrorMessage class="-mt-2 w-full" :message="error" />
				<h3 class="mt-4 text-base font-semibold">补丁配置</h3>
				<FormControl
					v-if="!applyToAllBenches"
					v-model="applyToBench"
					label="选择部署"
					type="select"
					variant="outline"
					:options="$resources.benches.data"
				/>
				<FormControl
					label="将补丁应用到所有活动部署"
					type="checkbox"
					v-model="applyToAllBenches"
				/>
				<FormControl
					label="应用补丁后构建资源"
					type="checkbox"
					v-model="buildAssets"
				/>
			</div>
		</template>
		<template v-slot:actions>
			<Button variant="solid" class="w-full" @click="applyPatch">
				应用补丁
			</Button>
		</template>
	</Dialog>
</template>
<script>
import {
	Button,
	Dialog,
	ErrorMessage,
	FeatherIcon,
	FileUploader,
	FormControl
} from 'jingrow-ui';

export default {
	name: 'PatchAppDialog',
	props: {
		app: [null, String],
		group: String
	},
	components: {
		Dialog,
		FormControl,
		ErrorMessage,
		FileUploader,
		Button,
		FeatherIcon
	},
	watch: {
		app(value) {
			this.show = !!value;
			this.applyToApp = value || '';
		},
		show(value) {
			this.error = '';
			if (value) {
				return;
			}

			setTimeout(this.clearApp, 150);
		}
	},
	data() {
		return {
			show: true,
			error: '',
			patch: '',
			patchURL: '',
			patchFileName: '',
			buildAssets: false,
			applyToApp: '',
			applyToBench: '',
			applyToAllBenches: false
		};
	},
	computed: {
		title() {
			const app = this.app || this.applyToApp;
			if (app) {
				return `应用补丁到 ${app}`;
			}

			return '应用补丁';
		}
	},
	methods: {
		clearApp() {
			this.$emit('clear-app-to-patch');
		},
		validate() {
			if (!this.$resources.benches.data.length) {
				this.error =
					'此部署组没有部署，无法应用补丁。';
				return false;
			}
if (this.patch && !this.patchFileName) {
				this.error = '请输入补丁文件名。';
				return false;
			}

			if (!this.patch && !this.patchURL) {
				this.error = '请输入补丁URL或选择一个补丁文件。';
				return false;
			}

			if (!this.applyToAllBenches && !this.applyToBench) {
				this.error =
					'请选择一个部署或勾选“将补丁应用到所有活动部署”。';
				return false;
			}

			if (!this.app && !this.applyToApp) {
				this.error = '请选择要打补丁的应用。';
				return false;
			}

			if (this.patchURL && !this.patchURL.endsWith('.patch')) {
				this.error =
					'补丁URL没有`.patch`扩展名。请输入有效的URL。';
				return false;
			}

			return true;
		},
		applyPatch() {
			if (!this.validate()) {
				return;
			}

			if (!this.patchFileName && this.patchURL) {
				this.patchFileName = this.patchURL.split('/').at(-1);
			}

			if (!this.patchFileName.endsWith('.patch')) {
				this.patchFileName += '.patch';
			}

			const app = this.app || this.applyToApp;
			const args = {
				release_group: this.group,
				app,
				patch_config: {
					patch: this.patch,
					filename: this.patchFileName,
					patch_url: this.patchURL,
					build_assets: this.buildAssets,
					patch_bench: this.applyToBench,
					patch_all_benches: this.applyToAllBenches
				}
			};

			this.$resources.applyPatch.submit(args);
		},
		async onPatchFileSelect(e) {
			this.error = '';
			const file = e.target.files?.[0];
			if (!file) {
				return;
			}

			this.patch = await file.text();
			this.patchFileName = file.name;
		},
		clear() {
			this.error = '';
			this.patch = '';
			this.patchFileName = '';
		},
		close() {
			this.show = false;
			this.clear();
		}
	},
	resources: {
		apps() {
			return {
				type: 'list',
				pagetype: 'Release Group App',
				parent: 'Release Group',
				auto: true,
				filters: {
					parenttype: 'Release Group',
					parent: this.group
				},
				onSuccess(data) {
					if (data.length === 1) {
						this.applyToApp = data[0].value;
					}
				},
				onError(data) {
					this.error = data;
				},
				transform(data) {
					return data.map(({ name }) => ({ value: name, label: name }));
				}
			};
		},
		benches() {
			return {
				type: 'list',
				pagetype: 'Bench',
				fields: ['name'],
				filters: {
					group: this.group,
					status: 'Active'
				},
				auto: true,
				onSuccess(data) {
					if (data.length > 0) {
						this.applyToBench = data.at(-1).value;
						return;
					}

					this.error =
						'此部署组没有部署，无法应用补丁。';
				},
				onError(data) {
					this.error = data;
				},
				transform(data) {
					return data.map(({ name }) => ({ value: name, label: name }));
				}
			};
		},
		applyPatch() {
			return {
				url: 'jcloud.api.bench.apply_patch',
				onSuccess() {
					this.close();
					this.$router.push({
						name: 'Release Group Detail Jobs',
						params: { name: this.group }
					});
				},
				onError(error) {
					if (error.messages.length) {
						this.error = error.messages.join('\n');
					} else {
						this.error = error.message;
					}
				}
			};
		}
	}
};
</script>