<script lang="ts" setup>
import Modal from './Modal.vue';
import { CREDENTIAL_EDIT_MODAL_KEY, SOURCE_CONTROL_PUSH_MODAL_KEY } from '@/constants';
import { computed, onMounted, ref } from 'vue';
import type { PropType } from 'vue';
import type { EventBus } from 'n8n-design-system/utils';
import type { SourceControlAggregatedFile } from '@/Interface';
import { useI18n, useLoadingService, useToast } from '@/composables';
import { useSourceControlStore } from '@/stores/sourceControl.store';
import { useUIStore } from '@/stores';
import { useRoute } from 'vue-router/composables';

const props = defineProps({
	data: {
		type: Object as PropType<{ eventBus: EventBus; status: SourceControlAggregatedFile[] }>,
		default: () => ({}),
	},
});

const loadingService = useLoadingService();
const uiStore = useUIStore();
const toast = useToast();
const { i18n } = useI18n();
const sourceControlStore = useSourceControlStore();
const route = useRoute();

const staged = ref<Record<string, boolean>>({});
const files = ref<SourceControlAggregatedFile[]>(props.data.status || []);

const commitMessage = ref('');
const loading = ref(true);
const context = ref<'workflow' | 'workflows' | 'credentials' | string>('');

const isSubmitDisabled = computed(() => {
	return !commitMessage.value || Object.values(staged.value).every((value) => !value);
});

onMounted(async () => {
	context.value = getContext();
	try {
		staged.value = getStagedFilesByContext(files.value);
	} catch (error) {
		toast.showError(error, i18n.baseText('error'));
	} finally {
		loading.value = false;
	}
});

function getContext() {
	if (route.fullPath.startsWith('/workflows')) {
		return 'workflows';
	} else if (
		route.fullPath.startsWith('/credentials') ||
		uiStore.modals[CREDENTIAL_EDIT_MODAL_KEY].open
	) {
		return 'credentials';
	} else if (route.fullPath.startsWith('/workflow/')) {
		return 'workflow';
	}

	return '';
}

function getStagedFilesByContext(files: SourceControlAggregatedFile[]): Record<string, boolean> {
	const stagedFiles: SourceControlAggregatedFile[] = [];
	if (context.value === 'workflows') {
		stagedFiles.push(...files.filter((file) => file.file.startsWith('workflows')));
	} else if (context.value === 'credentials') {
		stagedFiles.push(...files.filter((file) => file.file.startsWith('credentials')));
	} else if (context.value === 'workflow') {
		const workflowId = route.params.name as string;
		stagedFiles.push(...files.filter((file) => file.type === 'workflow' && file.id === workflowId));
	}

	return stagedFiles.reduce<Record<string, boolean>>((acc, file) => {
		acc[file.file] = true;
		return acc;
	}, {});
}

function setStagedStatus(file: SourceControlAggregatedFile, status: boolean) {
	staged.value = {
		...staged.value,
		[file.file]: status,
	};
}

function close() {
	uiStore.closeModal(SOURCE_CONTROL_PUSH_MODAL_KEY);
}

async function commitAndPush() {
	const fileNames = files.value.filter((file) => staged.value[file.file]).map((file) => file.file);

	loadingService.startLoading(i18n.baseText('settings.sourceControl.loading.push'));
	close();

	try {
		await sourceControlStore.pushWorkfolder({
			commitMessage: commitMessage.value,
			fileNames,
		});

		toast.showToast({
			title: i18n.baseText('settings.sourceControl.modals.push.success.title'),
			message: i18n.baseText('settings.sourceControl.modals.push.success.description'),
			type: 'success',
		});
	} catch (error) {
		toast.showError(error, i18n.baseText('error'));
	} finally {
		loadingService.stopLoading();
	}
}
</script>

<template>
	<Modal
		width="812px"
		:title="i18n.baseText('settings.sourceControl.modals.push.title')"
		:eventBus="data.eventBus"
		:name="SOURCE_CONTROL_PUSH_MODAL_KEY"
	>
		<template #content>
			<div :class="$style.container">
				<n8n-text>
					{{ i18n.baseText('settings.sourceControl.modals.push.description') }}
					<span v-if="context">
						{{ i18n.baseText(`settings.sourceControl.modals.push.description.${context}`) }}
					</span>
					<n8n-link
						:href="i18n.baseText('settings.sourceControl.modals.push.description.learnMore.url')"
					>
						{{ i18n.baseText('settings.sourceControl.modals.push.description.learnMore') }}
					</n8n-link>
				</n8n-text>

				<div v-if="files.length > 0">
					<n8n-text bold tag="p" class="mt-l mb-2xs">
						{{ i18n.baseText('settings.sourceControl.modals.push.filesToCommit') }}
					</n8n-text>
					<n8n-card
						v-for="file in files"
						:key="file.file"
						:class="$style.listItem"
						@click="setStagedStatus(file, !staged[file.file])"
					>
						<div :class="$style.listItemBody">
							<n8n-checkbox
								:value="staged[file.file]"
								:class="$style.listItemCheckbox"
								@input="setStagedStatus(file, !staged[file.file])"
							/>
							<n8n-text bold>
								<span v-if="file.status === 'deleted'">
									<span v-if="file.type === 'workflow'"> Workflow </span>
									<span v-if="file.type === 'credential'"> Credential </span>
									Id: {{ file.id }}
								</span>
								<span v-else>
									{{ file.name }}
								</span>
							</n8n-text>
							<n8n-badge :class="$style.listItemStatus">
								{{ file.status }}
							</n8n-badge>
						</div>
					</n8n-card>

					<n8n-text bold tag="p" class="mt-l mb-2xs">
						{{ i18n.baseText('settings.sourceControl.modals.push.commitMessage') }}
					</n8n-text>
					<n8n-input
						type="text"
						v-model="commitMessage"
						:placeholder="
							i18n.baseText('settings.sourceControl.modals.push.commitMessage.placeholder')
						"
					/>
				</div>
				<div v-else-if="!loading">
					<n8n-callout class="mt-l">
						{{ i18n.baseText('settings.sourceControl.modals.push.everythingIsUpToDate') }}
					</n8n-callout>
				</div>
			</div>
		</template>

		<template #footer>
			<div :class="$style.footer">
				<n8n-button type="tertiary" class="mr-2xs" @click="close">
					{{ i18n.baseText('settings.sourceControl.modals.push.buttons.cancel') }}
				</n8n-button>
				<n8n-button type="primary" :disabled="isSubmitDisabled" @click="commitAndPush">
					{{ i18n.baseText('settings.sourceControl.modals.push.buttons.save') }}
				</n8n-button>
			</div>
		</template>
	</Modal>
</template>

<style module lang="scss">
.container > * {
	overflow-wrap: break-word;
}

.actionButtons {
	display: flex;
	justify-content: flex-end;
	align-items: center;
}

.listItem {
	margin-top: var(--spacing-2xs);
	margin-bottom: var(--spacing-2xs);
	cursor: pointer;
	transition: border 0.3s ease;
	padding: var(--spacing-xs);

	&:hover {
		border-color: var(--color-foreground-dark);
	}

	&:first-child {
		margin-top: 0;
	}

	&:last-child {
		margin-bottom: 0;
	}

	.listItemBody {
		display: flex;
		flex-direction: row;
		align-items: center;

		.listItemCheckbox {
			display: inline-flex !important;
			margin-bottom: 0 !important;
			margin-right: var(--spacing-2xs);
		}

		.listItemStatus {
			margin-left: var(--spacing-2xs);
		}
	}
}

.footer {
	display: flex;
	flex-direction: row;
	justify-content: flex-end;
}
</style>
