<template>
	<div class="relative">
		<div
			v-if="!ready"
			class="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-8 transform"
		>
			<Spinner class="h-5 w-5 text-gray-600" />
		</div>
		<div :class="{ 'opacity-0': !ready }">
			<div v-show="!tryingMicroCharge">
				<label class="block">
					<span class="block text-xs text-gray-600">
						信用卡或借记卡
					</span>
					<div
						class="form-input mt-2 block h-[unset] w-full py-2 pl-3"
						ref="card-element"
					></div>
					<ErrorMessage class="mt-1" :message="cardErrorMessage" />
				</label>
				<FormControl
					class="mt-4"
					label="持卡人姓名"
					type="text"
					v-model="billingInformation.cardHolderName"
				/>
				<AddressForm
					v-if="!withoutAddress"
					class="mt-4"
					v-model:address="billingInformation"
					ref="address-form"
				/>
			</div>

			<div class="mt-3 space-y-4" v-show="tryingMicroCharge">
				<p class="text-base text-gray-700">
					我们正在尝试向您的卡收取
					<strong>{{ formattedMicroChargeAmount }}</strong> 以确保该卡有效。此金额将<strong>退还</strong>到您的账户。
				</p>

				<Button
					:loading="!microChargeCompleted"
					:loadingText="'正在验证卡片'"
				>
					卡片已验证
					<template #prefix>
						<GreenCheckIcon class="h-4 w-4" />
					</template>
				</Button>
			</div>

			<ErrorMessage class="mt-2" :message="errorMessage" />

			<div class="mt-6 flex items-center justify-between">
				<StripeLogo />
				<Button
					@click="clearForm"
					v-if="showAddAnotherCardButton"
					iconLeft="plus"
				>
					添加另一张卡
				</Button>
				<Button
					v-else-if="!tryingMicroCharge"
					variant="solid"
					@click="submit"
					:loading="addingCard"
				>
					验证并保存卡片
				</Button>
			</div>
		</div>
	</div>
</template>

<script>
import AddressForm from './AddressForm.vue';
import StripeLogo from '@/components/StripeLogo.vue';
import { loadStripe } from '@stripe/stripe-js';
import { toast } from 'vue-sonner';

export default {
	name: 'StripeCard',
	props: ['withoutAddress'],
	emits: ['complete'],
	components: {
		AddressForm,
		StripeLogo
	},
	data() {
		return {
			errorMessage: null,
			cardErrorMessage: null,
			ready: false,
			setupIntent: null,
			billingInformation: {
				cardHolderName: '',
				country: '',
				gstin: ''
			},
			gstNotApplicable: false,
			addingCard: false,
			tryingMicroCharge: false,
			showAddAnotherCardButton: false,
			microChargeCompleted: false
		};
	},
	async mounted() {
		await this.setupStripeIntent();
	},
	resources: {
		setupIntent() {
			return {
				url: 'jcloud.api.billing.get_publishable_key_and_setup_intent',
				async onSuccess(data) {
					//window.posthog.capture('init_client_add_card', 'fc_signup');
					let { publishable_key, setup_intent } = data;
					this.setupIntent = setup_intent;
					this.stripe = await loadStripe(publishable_key);
					this.elements = this.stripe.elements();
					let theme = this.$theme;
					let style = {
						base: {
							color: theme.colors.black,
							fontFamily: theme.fontFamily.sans.join(', '),
							fontSmoothing: 'antialiased',
							fontSize: '13px',
							'::placeholder': {
								color: theme.colors.gray['400']
							}
						},
						invalid: {
							color: theme.colors.red['600'],
							iconColor: theme.colors.red['600']
						}
					};
					this.card = this.elements.create('card', {
						hidePostalCode: true,
						style: style,
						classes: {
							complete: '',
							focus: 'bg-gray-100'
						}
					});
					this.card.mount(this.$refs['card-element']);

					this.card.addEventListener('change', event => {
this.cardErrorMessage = event.error?.message || null;
					});
					this.card.addEventListener('ready', () => {
						this.ready = true;
					});
				}
			};
		},
		countryList: 'jcloud.api.account.country_list',
		billingAddress() {
			return {
				url: 'jcloud.api.account.get_billing_information',
				params: {
					timezone: this.browserTimezone
				},
				auto: true,
				onSuccess(data) {
					this.billingInformation.country = data?.country;
					this.billingInformation.address = data?.address_line1;
					this.billingInformation.city = data?.city;
					this.billingInformation.state = data?.state;
					this.billingInformation.postal_code = data?.pincode;
				}
			};
		},
		setupIntentSuccess() {
			return {
				url: 'jcloud.api.billing.setup_intent_success',
				makeParams({ setupIntent }) {
					return {
						setup_intent: setupIntent,
						address: this.withoutAddress ? null : this.billingInformation
					};
				}
			};
		},
		verifyCardWithMicroCharge() {
			return {
				url: 'jcloud.api.billing.create_payment_intent_for_micro_debit',
				makeParams({ paymentMethodName }) {
					return {
						payment_method_name: paymentMethodName
					};
				}
			};
		}
	},
	methods: {
		async setupStripeIntent() {
			await this.$resources.setupIntent.submit();

			let { first_name, last_name = '' } = this.$team.pg.user_info;
			let fullname = first_name + ' ' + last_name;
			this.billingInformation.cardHolderName = fullname.trimEnd();
		},
		async submit() {
			this.addingCard = true;

			let message;
			if (!this.withoutAddress) {
				message = await this.$refs['address-form'].validateValues();
			}
			if (message) {
				this.errorMessage = message;
				this.addingCard = false;
				return;
			} else {
				this.errorMessage = null;
			}

			const { setupIntent, error } = await this.stripe.confirmCardSetup(
				this.setupIntent.client_secret,
				{
					payment_method: {
						card: this.card,
						billing_details: {
							name: this.billingInformation.cardHolderName,
							address: {
								line1: this.billingInformation.address,
								city: this.billingInformation.city,
								state: this.billingInformation.state,
								postal_code: this.billingInformation.postal_code,
								country: this.getCountryCode(this.billingInformation.country)
							}
						}
					}
				}
			);

			if (error) {
				this.addingCard = false;
				let declineCode = error.decline_code;
				let errorMessage = error.message;

				if (declineCode === 'do_not_honor') {
					this.errorMessage =
						"您的卡被拒绝了。可能是由于余额不足或您可能已超过每日限额。请尝试使用另一张卡或联系您的银行。";
					this.showAddAnotherCardButton = true;
				} else if (declineCode === 'transaction_not_allowed') {
					this.errorMessage =
						'您的卡被拒绝了。可能是由于您的卡的限制，如国际交易或在线支付。请尝试使用另一张卡或联系您的银行。';
					this.showAddAnotherCardButton = true;
				}
				// 修复重复错误消息
				else if (errorMessage != '您的卡号不完整。') {
					this.errorMessage = errorMessage;
				}
			} else {
				if (setupIntent?.status === 'succeeded') {
					this.$resources.setupIntentSuccess.submit(
						{
							setupIntent
						},
						{
							onSuccess: async ({ payment_method_name }) => {
								await this.verifyWithMicroChargeIfApplicable(
									payment_method_name
								);
								this.addingCard = false;
								toast.success('卡片添加成功');
							},
							onError: error => {
								console.error(error);
								this.addingCard = false;
								this.errorMessage = error.messages.join('\n');
								toast.error(this.errorMessage);
							}
						}
					);
				}
			}
		},
		async verifyWithMicroChargeIfApplicable(paymentMethodName) {
			const teamCurrency = this.$team.pg.currency;
			const verifyCardsWithMicroCharge = window.verify_cards_with_micro_charge;

			const isMicroChargeApplicable =
				verifyCardsWithMicroCharge === 'Both CNY and USD' ||
				(verifyCardsWithMicroCharge == 'Only CNY' && teamCurrency === 'CNY') ||
				(verifyCardsWithMicroCharge === 'Only USD' && teamCurrency === 'USD');
if (isMicroChargeApplicable) {
				await this._verifyWithMicroCharge(paymentMethodName);
			} else {
				this.$emit('complete');
			}
		},

		_verifyWithMicroCharge(paymentMethodName) {
			this.tryingMicroCharge = true;
			return this.$resources.verifyCardWithMicroCharge.submit(
				{ paymentMethodName },
				{
					onSuccess: async paymentIntent => {
						let { client_secret } = paymentIntent;
						let payload = await this.stripe.confirmCardPayment(client_secret, {
							payment_method: { card: this.card }
						});
						if (payload.paymentIntent?.status === 'succeeded') {
							this.microChargeCompleted = true;
							this.$emit('complete');
						}
					},
					onError: error => {
						console.error(error);
						this.tryingMicroCharge = false;
						this.errorMessage = error.messages.join('\n');
					}
				}
			);
		},
		getCountryCode(country) {
			let code = this.$resources.countryList.data.find(
				d => d.name === country
			).code;
			return code.toUpperCase();
		},
		async clearForm() {
			this.ready = false;
			this.errorMessage = null;
			this.showAddAnotherCardButton = false;
			this.card = null;
			this.setupStripeIntent();
		}
	},
	computed: {
		formattedMicroChargeAmount() {
			return this.$format.userCurrency(
				this.$team.pg.billing_info.micro_debit_charge_amount
			);
		},
		browserTimezone() {
			if (!window.Intl) {
				return null;
			}
			return Intl.DateTimeFormat().resolvedOptions().timeZone;
		}
	}
};
</script>