<template>
	<MkStickyContainer>
		<template #header
			><MkPageHeader
				v-model:tab="tab"
				:actions="headerActions"
				:tabs="headerTabs"
		/></template>
		<MkSpacer
			v-if="instance"
			:content-max="600"
			:margin-min="16"
			:margin-max="32"
		>
			<swiper
				:round-lengths="true"
				:touch-angle="25"
				:threshold="10"
				:centeredSlides="true"
				:modules="[Virtual]"
				:space-between="20"
				:virtual="true"
				:allow-touch-move="
					defaultStore.state.swipeOnMobile &&
					(deviceKind !== 'desktop' ||
						defaultStore.state.swipeOnDesktop)
				"
				@swiper="setSwiperRef"
				@slide-change="onSlideChange"
			>
				<swiper-slide>
					<div class="_formRoot">
						<div class="fnfelxur">
							<img :src="faviconUrl" alt="" class="icon" />
							<span class="name">{{
								instance.name || `(${i18n.ts.unknown})`
							}}</span>
						</div>
						<MkKeyValue :copy="host" oneline style="margin: 1em 0">
							<template #key>Host</template>
							<template #value
								><span class="_monospace"
									><MkLink :url="`https://${host}`">{{
										host
									}}</MkLink></span
								></template
							>
						</MkKeyValue>
						<MkKeyValue oneline style="margin: 1em 0">
							<template #key>{{ i18n.ts.software }}</template>
							<template #value
								><span class="_monospace"
									>{{
										instance.softwareName ||
										`(${i18n.ts.unknown})`
									}}
									/
									{{
										instance.softwareVersion ||
										`(${i18n.ts.unknown})`
									}}</span
								></template
							>
						</MkKeyValue>
						<MkKeyValue oneline style="margin: 1em 0">
							<template #key>{{
								i18n.ts.administrator
							}}</template>
							<template #value
								>{{
									instance.maintainerName ||
									`(${i18n.ts.unknown})`
								}}
								({{
									instance.maintainerEmail ||
									`(${i18n.ts.unknown})`
								}})</template
							>
						</MkKeyValue>
						<MkKeyValue>
							<template #key>{{ i18n.ts.description }}</template>
							<template #value>{{
								instance.description
							}}</template>
						</MkKeyValue>

						<FormSection v-if="iAmAdmin">
							<template #label>Moderation</template>
							<FormSuspense :p="init">
								<FormSwitch
									v-model="suspended"
									class="_formBlock"
									@update:modelValue="toggleSuspend"
									>{{
										i18n.ts.stopActivityDelivery
									}}</FormSwitch
								>
								<FormSwitch
									v-model="isBlocked"
									class="_formBlock"
									@update:modelValue="toggleBlock"
									>{{ i18n.ts.blockThisInstance }}</FormSwitch
								>
								<FormSwitch
									v-model="isSilenced"
									class="_formBlock"
									@update:modelValue="toggleSilence"
									>{{
										i18n.ts.silenceThisInstance
									}}</FormSwitch
								>
							</FormSuspense>
							<MkButton @click="refreshMetadata"
								><i
									class="ph-arrows-clockwise ph-bold ph-lg"
								></i>
								Refresh metadata</MkButton
							>
						</FormSection>

						<FormSection>
							<MkKeyValue oneline style="margin: 1em 0">
								<template #key>{{
									i18n.ts.registeredAt
								}}</template>
								<template #value
									><MkTime
										mode="detail"
										:time="instance.caughtAt"
								/></template>
							</MkKeyValue>
							<MkKeyValue oneline style="margin: 1em 0">
								<template #key>{{
									i18n.ts.updatedAt
								}}</template>
								<template #value
									><MkTime
										mode="detail"
										:time="instance.infoUpdatedAt"
								/></template>
							</MkKeyValue>
							<MkKeyValue oneline style="margin: 1em 0">
								<template #key>{{
									i18n.ts.latestRequestSentAt
								}}</template>
								<template #value
									><MkTime
										v-if="instance.latestRequestSentAt"
										:time="instance.latestRequestSentAt"
									/><span v-else>N/A</span></template
								>
							</MkKeyValue>
							<MkKeyValue oneline style="margin: 1em 0">
								<template #key>{{
									i18n.ts.latestStatus
								}}</template>
								<template #value>{{
									instance.latestStatus
										? instance.latestStatus
										: "N/A"
								}}</template>
							</MkKeyValue>
							<MkKeyValue oneline style="margin: 1em 0">
								<template #key>{{
									i18n.ts.latestRequestReceivedAt
								}}</template>
								<template #value
									><MkTime
										v-if="instance.latestRequestReceivedAt"
										:time="instance.latestRequestReceivedAt"
									/><span v-else>N/A</span></template
								>
							</MkKeyValue>
						</FormSection>

						<FormSection>
							<MkKeyValue oneline style="margin: 1em 0">
								<template #key>Following (Pub)</template>
								<template #value>{{
									number(instance.followingCount)
								}}</template>
							</MkKeyValue>
							<MkKeyValue oneline style="margin: 1em 0">
								<template #key>Followers (Sub)</template>
								<template #value>{{
									number(instance.followersCount)
								}}</template>
							</MkKeyValue>
						</FormSection>

						<FormSection>
							<template #label>Well-known resources</template>
							<FormLink
								:to="`https://${host}/.well-known/host-meta`"
								external
								style="margin-bottom: 8px"
								>host-meta</FormLink
							>
							<FormLink
								:to="`https://${host}/.well-known/host-meta.json`"
								external
								style="margin-bottom: 8px"
								>host-meta.json</FormLink
							>
							<FormLink
								:to="`https://${host}/.well-known/nodeinfo`"
								external
								style="margin-bottom: 8px"
								>nodeinfo</FormLink
							>
							<FormLink
								:to="`https://${host}/robots.txt`"
								external
								style="margin-bottom: 8px"
								>robots.txt</FormLink
							>
							<FormLink
								:to="`https://${host}/manifest.json`"
								external
								style="margin-bottom: 8px"
								>manifest.json</FormLink
							>
						</FormSection>
					</div>
				</swiper-slide>
				<swiper-slide>
					<div class="_formRoot">
						<div class="cmhjzshl">
							<div class="selects">
								<MkSelect
									v-model="chartSrc"
									style="margin: 0 10px 0 0; flex: 1"
								>
									<option value="instance-requests">
										{{ i18n.ts._instanceCharts.requests }}
									</option>
									<option value="instance-users">
										{{ i18n.ts._instanceCharts.users }}
									</option>
									<option value="instance-users-total">
										{{ i18n.ts._instanceCharts.usersTotal }}
									</option>
									<option value="instance-notes">
										{{ i18n.ts._instanceCharts.notes }}
									</option>
									<option value="instance-notes-total">
										{{ i18n.ts._instanceCharts.notesTotal }}
									</option>
									<option value="instance-ff">
										{{ i18n.ts._instanceCharts.ff }}
									</option>
									<option value="instance-ff-total">
										{{ i18n.ts._instanceCharts.ffTotal }}
									</option>
									<option value="instance-drive-usage">
										{{ i18n.ts._instanceCharts.cacheSize }}
									</option>
									<option value="instance-drive-usage-total">
										{{
											i18n.ts._instanceCharts
												.cacheSizeTotal
										}}
									</option>
									<option value="instance-drive-files">
										{{ i18n.ts._instanceCharts.files }}
									</option>
									<option value="instance-drive-files-total">
										{{ i18n.ts._instanceCharts.filesTotal }}
									</option>
								</MkSelect>
							</div>
							<div class="charts">
								<div class="label">
									{{ i18n.t("recentNHours", { n: 90 }) }}
								</div>
								<MkChart
									class="chart"
									:src="chartSrc"
									span="hour"
									:limit="90"
									:args="{ host: host }"
									:detailed="true"
								></MkChart>
								<div class="label">
									{{ i18n.t("recentNDays", { n: 90 }) }}
								</div>
								<MkChart
									class="chart"
									:src="chartSrc"
									span="day"
									:limit="90"
									:args="{ host: host }"
									:detailed="true"
								></MkChart>
							</div>
						</div>
					</div>
				</swiper-slide>
				<swiper-slide>
					<div class="_formRoot">
						<MkPagination
							v-slot="{ items }"
							:pagination="usersPagination"
							style="
								display: grid;
								grid-template-columns: repeat(
									auto-fill,
									minmax(270px, 1fr)
								);
								grid-gap: 12px;
							"
						>
							<MkA
								v-for="user in items"
								:key="user.id"
								v-tooltip.mfm="
									`Last posted: ${new Date(
										user.updatedAt,
									).toLocaleString()}`
								"
								class="user"
								:to="`/user-info/${user.id}`"
							>
								<MkUserCardMini :user="user" />
							</MkA>
						</MkPagination>
					</div>
				</swiper-slide>
				<swiper-slide>
					<div class="_formRoot">
						<MkObjectView tall :value="instance"> </MkObjectView>
					</div>
				</swiper-slide>
			</swiper>
		</MkSpacer>
	</MkStickyContainer>
</template>

<script lang="ts" setup>
import { watch, ref, computed } from "vue";
import { Virtual } from "swiper/modules";
import { Swiper, SwiperSlide } from "swiper/vue";
import type * as firefish from "firefish-js";
import MkChart from "@/components/MkChart.vue";
import MkObjectView from "@/components/MkObjectView.vue";
import FormLink from "@/components/form/link.vue";
import MkLink from "@/components/MkLink.vue";
import MkButton from "@/components/MkButton.vue";
import FormSection from "@/components/form/section.vue";
import MkKeyValue from "@/components/MkKeyValue.vue";
import MkSelect from "@/components/form/select.vue";
import FormSwitch from "@/components/form/switch.vue";
import * as os from "@/os";
import number from "@/filters/number";
import { iAmAdmin } from "@/account";
import { definePageMetadata } from "@/scripts/page-metadata";
import { deviceKind } from "@/scripts/device-kind";
import { defaultStore } from "@/store";
import { i18n } from "@/i18n";
import MkUserCardMini from "@/components/MkUserCardMini.vue";
import MkPagination from "@/components/MkPagination.vue";
import "swiper/scss";
import "swiper/scss/virtual";
import { getProxiedImageUrlNullable } from "@/scripts/media-proxy";

type AugmentedInstanceMetadata = firefish.entities.DetailedInstanceMetadata & {
	blockedHosts: string[];
	silencedHosts: string[];
};
type AugmentedInstance = firefish.entities.Instance & {
	isBlocked: boolean;
	isSilenced: boolean;
};

const props = defineProps<{
	host: string;
}>();

let tabs = ["overview"];
if (iAmAdmin) tabs.push("chart", "users", "raw");
const tab = ref(tabs[0]);
watch(tab, () => syncSlide(tabs.indexOf(tab.value)));

const chartSrc = ref("instance-requests");
const meta = ref<AugmentedInstanceMetadata | null>(null);
const instance = ref<AugmentedInstance | null>(null);
const suspended = ref(false);
const isBlocked = ref(false);
const isSilenced = ref(false);
const faviconUrl = ref(null);

const usersPagination = {
	endpoint: iAmAdmin ? "admin/show-users" : ("users" as const),
	limit: 10,
	params: {
		sort: "+updatedAt",
		state: "all",
		hostname: props.host,
	},
	offsetMode: true,
};

async function fetch() {
	if (iAmAdmin)
		meta.value = (await os.api("admin/meta")) as AugmentedInstanceMetadata;
	instance.value = (await os.api("federation/show-instance", {
		host: props.host,
	})) as AugmentedInstance;
	suspended.value = instance.value.isSuspended;
	isBlocked.value = instance.value.isBlocked;
	isSilenced.value = instance.value.isSilenced;
	faviconUrl.value =
		getProxiedImageUrlNullable(instance.value.faviconUrl, "preview") ??
		getProxiedImageUrlNullable(instance.value.iconUrl, "preview");
}

async function toggleBlock() {
	if (meta.value == null) return;
	if (!instance.value) {
		throw new Error(`Instance info not loaded`);
	}
	let blockedHosts: string[];
	if (isBlocked.value) {
		blockedHosts = meta.value.blockedHosts.concat([instance.value.host]);
	} else {
		blockedHosts = meta.value.blockedHosts.filter(
			(x) => x !== instance.value!.host,
		);
	}
	await os.api("admin/update-meta", {
		blockedHosts,
	});
}

async function toggleSilence() {
	if (meta.value == null) return;
	if (!instance.value) {
		throw new Error(`Instance info not loaded`);
	}
	let silencedHosts: string[];
	if (isSilenced.value) {
		silencedHosts = meta.value.silencedHosts.concat([instance.value.host]);
	} else {
		silencedHosts = meta.value.silencedHosts.filter(
			(x) => x !== instance.value!.host,
		);
	}
	await os.api("admin/update-meta", {
		silencedHosts,
	});
}

async function toggleSuspend(v) {
	await os.api("admin/federation/update-instance", {
		host: instance.value.host,
		isSuspended: suspended.value,
	});
}

function refreshMetadata() {
	os.api("admin/federation/refresh-remote-instance-metadata", {
		host: instance.value.host,
	});
	os.alert({
		text: "Refresh requested",
	});
}

fetch();

const headerActions = computed(() => [
	{
		text: `https://${props.host}`,
		icon: "ph-arrow-square-out ph-bold ph-lg",
		handler: () => {
			window.open(`https://${props.host}`, "_blank");
		},
	},
]);

let theTabs = [
	{
		key: "overview",
		title: i18n.ts.overview,
		icon: "ph-info ph-bold ph-lg",
	},
];

if (iAmAdmin) {
	theTabs.push(
		{
			key: "chart",
			title: i18n.ts.charts,
			icon: "ph-chart-bar ph-bold ph-lg",
		},
		{
			key: "users",
			title: i18n.ts.users,
			icon: "ph-users ph-bold ph-lg",
		},
		{
			key: "raw",
			title: "Raw",
			icon: "ph-code ph-bold ph-lg",
		},
	);
}

const headerTabs = computed(() => theTabs);

definePageMetadata({
	title: props.host,
	icon: "ph-hard-drives ph-bold ph-lg",
});

let swiperRef = null;

function setSwiperRef(swiper) {
	swiperRef = swiper;
	syncSlide(tabs.indexOf(tab.value));
}

function onSlideChange() {
	tab.value = tabs[swiperRef.activeIndex];
}

function syncSlide(index) {
	swiperRef.slideTo(index);
}
</script>

<style lang="scss" scoped>
.fnfelxur {
	display: flex;
	align-items: center;

	> .icon {
		display: block;
		margin: 0 16px 0 0;
		height: 64px;
		border-radius: 8px;
	}

	> .name {
		word-break: break-all;
	}
}

.cmhjzshl {
	> .selects {
		display: flex;
		margin: 0 0 16px 0;
	}

	> .charts {
		> .label {
			margin-bottom: 12px;
			font-weight: bold;
		}
	}
}
</style>
