<template>
	<div>
		<div>
			<header
				class="sticky top-0 z-10 flex items-center justify-between border-b bg-white px-5 py-2.5"
			>
				<Breadcrumbs :items="[{ label: 'Sites', route: { name: 'Sites' } }]">
					<template v-if="this.$account?.team.enabled" #actions>
						<Button
							variant="solid"
							icon-left="plus"
							class="ml-2"
							label="Create"
							@click="validateCreateSite"
						>
						</Button>
					</template>
				</Breadcrumbs>
			</header>

			<div class="my-5 space-y-2 px-5">
				<div v-if="!$account.team.enabled">
					<Alert title="Your account is disabled">
						Enable your account to start creating sites
						<template #actions>
							<Button variant="solid" route="/settings/profile">
								Enable Account
							</Button>
						</template>
					</Alert>
				</div>
				<AlertBillingInformation />
				<template v-if="showUnpaidInvoiceAlert">
					<Alert
						v-if="latestUnpaidInvoice.payment_mode === 'Prepaid Credits'"
						title="Your last invoice payment has failed."
					>
						Please add
						<strong>
							{{ latestUnpaidInvoice.currency }}
							{{ latestUnpaidInvoice.amount_due }}
						</strong>
						more in credits.
						<template #actions>
							<Button
								@click="
									$account.team.billing_address
										? (showPrepaidCreditsDialog = true)
										: (showAddressDialog = true)
								"
								variant="solid"
							>
								Add Credits
							</Button>
						</template>
					</Alert>

					<Alert v-else title="Your last invoice payment has failed.">
						Pay now for uninterrupted services.
						<template v-if="this.$resources.latestUnpaidInvoice.data" #actions>
							<router-link
								:to="{ path: '/billing', query: { invoiceStatus: 'Unpaid' } }"
							>
								<Button variant="solid"> Go to Billing </Button>
							</router-link>
						</template>
					</Alert>

					<UpdateBillingDetails
						v-if="showAddressDialog"
						v-model="showAddressDialog"
						@updated="
							showAddressDialog = false;
							showPrepaidCreditsDialog = true;
							$resources.billingDetails.reload();
						"
					/>

					<PrepaidCreditsDialog
						v-if="showPrepaidCreditsDialog"
						v-model:show="showPrepaidCreditsDialog"
						:minimum-amount="Math.ceil(latestUnpaidInvoice.amount_due)"
						@success="handleAddPrepaidCreditsSuccess"
					/>
				</template>
			</div>
			<div class="mx-5">
				<div class="pb-20">
					<div class="flex">
						<div class="flex w-full space-x-2 pb-4">
							<FormControl label="Search Sites" v-model="searchTerm">
								<template #prefix>
									<FeatherIcon name="search" class="w-4 text-gray-600" />
								</template>
							</FormControl>
							<FormControl
								label="Status"
								class="mr-8"
								type="select"
								:options="siteStatusFilterOptions"
								v-model="site_status"
							/>
							<FormControl
								v-if="$resources.siteTags.data.length > 0"
								label="Tag"
								class="mr-8"
								type="select"
								:options="siteTagFilterOptions"
								v-model="site_tag"
							/>
						</div>
					</div>
					<Table
						:columns="[
							{ label: 'Site Name', name: 'name', width: 2 },
							{ label: 'Status', name: 'status', width: 1 },
							{ label: 'Region', name: 'region', width: 0.5 },
							{ label: 'Tags', name: 'tags', width: 1 },
							{ label: 'Plan', name: 'plan', width: 1.5 },
							{ label: '', name: 'actions', width: 0.5 }
						]"
						:rows="sites"
						v-slot="{ rows, columns }"
					>
						<TableHeader class="mb-4 hidden lg:grid" />
						<div
							v-for="group in groups"
							:key="group.group"
							class="mb-4 rounded border"
						>
							<div
								class="flex w-full items-center rounded-t bg-gray-50 px-3 py-2 text-base"
							>
								<span class="font-semibold text-gray-900">
									{{ group.title }}
								</span>
								<span v-if="!group.public" class="ml-2 text-gray-600">{{
									group.version
								}}</span>
								<Button
									v-if="!group.public"
									variant="ghost"
									class="ml-auto"
									:route="{ name: 'Bench', params: { benchName: group.group } }"
								>
									View Bench
								</Button>
								<div v-else class="h-7" />
							</div>

							<TableRow
								v-for="(row, index) in sitesByGroup[group.group]"
								:key="row.name"
								:row="row"
								:class="index === 0 ? 'rounded-b' : 'rounded'"
							>
								<TableCell v-for="column in columns">
									<Badge
										v-if="column.name === 'status'"
										:label="$siteStatus(row)"
									/>
									<div
										v-else-if="column.name === 'tags'"
										class="hidden space-x-1 lg:flex"
									>
										<Badge
											v-for="(tag, i) in row.tags.slice(0, 1)"
											theme="blue"
											:label="tag"
										/>
										<Tooltip
											v-if="row.tags.length > 1"
											:text="row.tags.slice(1).join(', ')"
										>
											<Badge
												v-if="row.tags.length > 1"
												:label="`+${row.tags.length - 1}`"
											/>
										</Tooltip>
										<span v-if="row.tags.length == 0">-</span>
									</div>
									<span
										v-else-if="column.name === 'plan'"
										class="hidden md:block"
									>
										{{
											row.plan
												? `${$planTitle(row.plan)}${
														row.plan.price_usd > 0 ? '/mo' : ''
												  }`
												: ''
										}}
									</span>
									<div
										v-else-if="column.name === 'region'"
										class="hidden md:block"
									>
										<img
											v-if="row.server_region_info.image"
											class="h-4"
											:src="row.server_region_info.image"
											:alt="`Flag of ${row.server_region_info.title}`"
											:title="row.server_region_info.title"
										/>
										<span class="text-base text-gray-700" v-else>
											{{ row.server_region_info.title }}
										</span>
									</div>
									<div
										class="w-full text-right"
										v-else-if="column.name == 'actions'"
									>
										<Dropdown
											v-if="['Active', 'Updating'].includes(row.status)"
											@click.prevent
											:options="dropdownItems(row)"
										>
											<template v-slot="{ open }">
												<Button
													:variant="open ? 'subtle' : 'ghost'"
													icon="more-horizontal"
												/>
											</template>
										</Dropdown>
									</div>
									<span v-else>{{ row[column.name] || '' }}</span>
								</TableCell>
							</TableRow>
						</div>
						<div class="mt-8 flex items-center justify-center">
							<LoadingText
								v-if="$resources.allSites.loading && !$resources.allSites.data"
							/>
							<div
								v-else-if="$resources.allSites.fetched && rows.length === 0"
								class="text-base text-gray-700"
							>
								No Sites
							</div>
						</div>
					</Table>

					<Dialog
						:options="{
							title: 'Login As Administrator',
							actions: [
								{
									label: 'Proceed',
									variant: 'solid',
									onClick: proceedWithLoginAsAdmin
								}
							]
						}"
						v-model="showReasonForAdminLoginDialog"
					>
						<template #body-content>
							<FormControl
								label="Reason for logging in as Administrator"
								type="textarea"
								v-model="reasonForAdminLogin"
								required
							/>
							<ErrorMessage class="mt-3" :message="errorMessage" />
						</template>
					</Dialog>
				</div>
			</div>
		</div>
	</div>
</template>
<script>
import { defineAsyncComponent } from 'vue';
import Table from '@/components/Table/Table.vue';
import TableHeader from '@/components/Table/TableHeader.vue';
import TableRow from '@/components/Table/TableRow.vue';
import TableCell from '@/components/Table/TableCell.vue';
import { loginAsAdmin } from '@/controllers/loginAsAdmin';
import AlertBillingInformation from '@/components/AlertBillingInformation.vue';
import { notify } from '@/utils/toast';

export default {
	name: 'Sites',
	pageMeta() {
		return {
			title: 'Sites - 今果 Jingrow'
		};
	},
	props: ['bench'],
	components: {
		Table,
		TableHeader,
		TableRow,
		TableCell,
		PrepaidCreditsDialog: defineAsyncComponent(() =>
			import('@/components/PrepaidCreditsDialog.vue')
		),
		StripeCard: defineAsyncComponent(() =>
			import('@/components/StripeCard.vue')
		),
		AlertBillingInformation,
		UpdateBillingDetails: defineAsyncComponent(() =>
			import('@/components/UpdateBillingDetails.vue')
		)
	},
	data() {
		return {
			showPrepaidCreditsDialog: false,
			showAddCardDialog: false,
			searchTerm: '',
			reasonForAdminLogin: '',
			errorMessage: null,
			showReasonForAdminLoginDialog: false,
			siteForLogin: null,
			site_status: 'All',
			site_tag: '',
			showAddressDialog: false
		};
	},
	resources: {
		allSites() {
			return {
				url: 'jcloud.api.site.all',
				params: {
					site_filter: { status: this.site_status, tag: this.site_tag }
				},
				auto: true,
				cache: [
					'SiteList',
					this.site_status,
					this.site_tag,
					this.$account.team.name
				]
			};
		},
		siteTags: { url: 'jcloud.api.site.site_tags', auto: true, initialData: [] },
		latestUnpaidInvoice: {
			url: 'jcloud.api.billing.get_latest_unpaid_invoice',
			auto: true
		},
		loginAsAdmin() {
			return loginAsAdmin('placeholderSite'); // So that RM does not yell at first load
		},
		billingDetails: 'jcloud.api.billing.details'
	},
	mounted() {
		this.$socket.on('agent_job_update', this.onAgentJobUpdate);
		this.$socket.on('list_update', this.onSiteUpdate);
	},
	unmounted() {
		this.$socket.off('agent_job_update', this.onAgentJobUpdate);
		this.$socket.off('list_update', this.onSiteUpdate);
	},
	methods: {
		validateCreateSite() {
			if (!this.$account.hasBillingInfo) {
				this.showAddCardDialog = true;
			} else if (
				this.$account.billing_info.has_unpaid_invoices &&
				!this.$account.team.free_account
			) {
				notify({
					title:
						'Please settle your unpaid invoices from the billing tab in order to create new sites',
					icon: 'info',
					color: 'yellow'
				});
			} else {
				this.$router.replace('/sites/new');
			}
		},
		onAgentJobUpdate(data) {
			if (!(data.name === 'New Site' || data.name === 'New Site from Backup'))
				return;
			if (data.status === 'Success' && data.user === this.$account.user.name) {
				this.reload();
				notify({
					title: 'Site creation complete!',
					message: 'Login to your site and complete the setup wizard',
					icon: 'check',
					color: 'green'
				});
			}
		},
		onSiteUpdate(event) {
			// Refresh if the event affects any of the sites in the list view
			// TODO: Listen to a more granular event than list_update
			if (event.pagetype === 'Site') {
				let sites = this.sites;
				if (
					event.user === this.$account.user.name ||
					sites.includes(event.name)
				) {
					this.reload();
				}
			}
		},
		reload() {
			// refresh if currently not loading and have not reloaded in the last 5 seconds
			if (
				!this.$resources.allSites.loading &&
				new Date() - this.$resources.allSites.lastLoaded > 5000
			) {
				this.$resources.allSites.reload();
			}
		},
		handleAddPrepaidCreditsSuccess() {
			this.$resources.latestUnpaidInvoice.reload();
			this.showPrepaidCreditsDialog = false;
		},
		dropdownItems(site) {
			return [
				{
					label: 'Visit Site',
					onClick: () => {
						window.open(`https://${site.name}`, '_blank');
					}
				},
				{
					label: 'Login As Admin',
					onClick: () => {
						if (this.$account.team.name === site.team) {
							return this.$resources.loginAsAdmin.submit({
								name: site.name
							});
						}

						this.siteForLogin = site.name;
						this.showReasonForAdminLoginDialog = true;
					}
				}
			];
		},
		proceedWithLoginAsAdmin() {
			this.errorMessage = '';

			if (!this.reasonForAdminLogin.trim()) {
				this.errorMessage = 'Reason is required';
				return;
			}

			this.$resources.loginAsAdmin.submit({
				name: this.siteForLogin,
				reason: this.reasonForAdminLogin
			});

			this.showReasonForAdminLoginDialog = false;
		}
	},
	computed: {
		sites() {
			if (!this.$resources.allSites.data) {
				return [];
			}
			let sites = this.$resources.allSites.data.filter(site =>
				this.$account.hasPermission(site.name, '', true)
			);
			if (this.searchTerm) {
				return sites.filter(site =>
					site.name.toLowerCase().includes(this.searchTerm.toLowerCase())
				);
			}
			return sites;
		},
		sitesByGroup() {
			let sitesByGroup = {};

			for (let site of this.sites) {
				let group = site.group;
				if (!sitesByGroup[group]) {
					sitesByGroup[group] = [];
				}
				site.route = {
					name: 'SiteOverview',
					params: {
						siteName: site.name
					}
				};
				sitesByGroup[group].push(site);
			}

			return sitesByGroup;
		},
		groups() {
			let seen = [];
			let groups = [];
			for (let site of this.sites) {
				if (site.public) {
					site.title = 'Shared';
					site.group = 'Shared';
				}
				if (!seen.includes(site.group)) {
					seen.push(site.group);
					if (site.public)
						groups.unshift({
							title: site.title,
							group: site.group,
							public: site.public,
							version: site.version
						});
					else
						groups.push({
							title: site.title,
							group: site.group,
							public: site.public,
							version: site.version
						});
				}
			}
			return groups;
		},
		showUnpaidInvoiceAlert() {
			if (!this.latestUnpaidInvoice) {
				return;
			}
			return !(
				this.$account.team.jerp_partner || this.$account.team.free_account
			);
		},
		latestUnpaidInvoice() {
			if (this.$resources.latestUnpaidInvoice.data) {
				return this.$resources.latestUnpaidInvoice.data;
			}
		},
		siteStatusFilterOptions() {
			return [
				{
					label: 'All',
					value: 'All'
				},
				{
					label: 'Active',
					value: 'Active'
				},
				{
					label: 'Broken',
					value: 'Broken'
				},
				{
					label: 'Inactive',
					value: 'Inactive'
				},
				{
					label: 'Trial',
					value: 'Trial'
				},
				{
					label: 'Update Available',
					value: 'Update Available'
				}
			];
		},
		siteTagFilterOptions() {
			const defaultOptions = [
				{
					label: '',
					value: ''
				}
			];

			if (!this.$resources.siteTags.data) return defaultOptions;

			return [
				...defaultOptions,
				...this.$resources.siteTags.data.map(tag => ({
					label: tag,
					value: tag
				}))
			];
		}
	}
};
</script>
