import { defineStore } from "pinia";
import { ref } from "vue";
import { get_workflow_elements, validate_transitions } from "./utils";
import { useManualRefHistory, onKeyDown } from "@vueuse/core";

export const useStore = defineStore("workflow-builder-store", () => {
	let workflow_name = ref(null);
	let workflow_pg = ref(null);
	let workflow_pg_fields = ref([]);
	let workflow = ref({ elements: [], selected: null });
	let workflowfields = ref([]);
	let statefields = ref([]);
	let transitionfields = ref([]);
	let ref_history = ref(null);

	async function fetch() {
		await jingrow.model.clear_pg("Workflow", workflow_name.value);
		await jingrow.model.with_pg("Workflow", workflow_name.value);

		workflow_pg.value = jingrow.get_pg("Workflow", workflow_name.value);
		await jingrow.model.with_pagetype(workflow_pg.value.document_type);

		if (!workflowfields.value.length) {
			await jingrow.model.with_pagetype("Workflow");
			workflowfields.value = jingrow.get_meta("Workflow").fields;
		}

		if (!statefields.value.length) {
			await jingrow.model.with_pagetype("Workflow Page State");
			statefields.value = jingrow.get_meta("Workflow Page State").fields;
		}

		if (!transitionfields.value.length) {
			await jingrow.model.with_pagetype("Workflow Transition");
			transitionfields.value = jingrow.get_meta("Workflow Transition").fields;
		}

		if (!workflow_pg_fields.value.length) {
			let pg_type = workflow_pg.value.document_type;
			await jingrow.model.with_pagetype(pg_type);
			workflow_pg_fields.value = jingrow.meta
				.get_pagefields(pg_type, null, {
					fieldtype: ["not in", jingrow.model.no_value_type],
				})
				.sort((a, b) => {
					if (a.label && b.label) {
						return a.label.localeCompare(b.label);
					}
				})
				.map((df) => ({
					label: `${df.label || __("No Label")} (${df.fieldtype})`,
					value: df.fieldname,
				}));
		}

		const workflow_data =
			(workflow_pg.value.workflow_data &&
				typeof workflow_pg.value.workflow_data == "string" &&
				JSON.parse(workflow_pg.value.workflow_data)) ||
			[];

		workflow.value.elements = get_workflow_elements(workflow_pg.value, workflow_data);

		setup_undo_redo();
		setup_breadcrumbs();
	}

	function reset_changes() {
		fetch();
	}

	async function save_changes() {
		jingrow.dom.freeze(__("Saving..."));

		try {
			let pg = workflow_pg.value;
			pg.states = get_updated_states();
			pg.transitions = get_updated_transitions();
			validate_workflow(pg);
			const workflow_data = clean_workflow_data();
			pg.workflow_data = JSON.stringify(workflow_data);
			await jingrow.call("jingrow.client.save", { pg });
			jingrow.toast(__("Workflow updated successfully"));
			fetch();
		} catch (e) {
			console.error(e);
		} finally {
			jingrow.dom.unfreeze();
		}
	}

	function validate_workflow(pg) {
		if (pg.is_active && (!pg.states.length || !pg.transitions.length)) {
			let message = "Workflow must have atleast one state and transition";
			jingrow.throw({
				message: __(message),
				title: __("Missing Values Required"),
				indicator: "orange",
			});
		}
	}

	function clean_workflow_data() {
		return workflow.value.elements.map((el) => {
			const {
				selected,
				dragging,
				resizing,
				data,
				events,
				initialized,
				sourceNode,
				targetNode,
				...obj
			} = el;

			if (el.type == "action") {
				obj.data = {
					from_id: data.from_id,
					to_id: data.to_id,
				};
			}

			return obj;
		});
	}

	function setup_breadcrumbs() {
		let breadcrumbs = `
			<li><a href="/app/workflow">${__("Workflow")}</a></li>
			<li><a href="/app/workflow/${workflow_name.value}">${__(workflow_name.value)}</a></li>
			<li class="disabled"><a href="#">${__("Workflow Builder")}</a></li>
		`;
		jingrow.breadcrumbs.clear();
		jingrow.breadcrumbs.$breadcrumbs.append(breadcrumbs);
	}

	function get_state_df(data) {
		let pg_status_map = {
			Draft: 0,
			Submitted: 1,
			Cancelled: 2,
		};
		data.pg_status = pg_status_map[data.pg_status];
		return data;
	}

	function get_updated_states() {
		let states = [];
		workflow.value.elements.forEach((element) => {
			if (element.type == "state") {
				element.data.workflow_builder_id = element.id;
				states.push(get_state_df(element.data));
			}
		});
		return states;
	}

	function get_transition_df(data) {
		return data;
	}

	function get_updated_transitions() {
		let transitions = [];
		let actions = [];

		workflow.value.elements.forEach((element) => {
			if (element.type == "action") {
				element.data.workflow_builder_id = element.id;
				actions.push(element);
			}
		});

		actions.forEach((action) => {
			let states = workflow.value.elements.filter((e) => e.type == "state");

			let state = states.find(
				(state) => state.data.workflow_builder_id == action.data.from_id
			);
			let next_state = states.find(
				(state) => state.data.workflow_builder_id == action.data.to_id
			);

			if (action.data.to.length === 0 && next_state != undefined) {
				action.data.to = next_state.data.state;
			}

			let error = validate_transitions(state.data, next_state.data);
			if (error) {
				jingrow.throw({
					message: error,
					title: __("Invalid Transition"),
				});
			}
			transitions.push(
				get_transition_df({
					...action.data,
					state: action.data.from,
					next_state: action.data.to,
				})
			);
		});

		return transitions;
	}

	let undo_redo_keyboard_event = () =>
		onKeyDown(true, (e) => {
			if (!ref_history.value) return;
			if (e.ctrlKey || e.metaKey) {
				if (e.key === "z" && !e.shiftKey && ref_history.value.canUndo) {
					ref_history.value.undo();
				} else if (e.key === "z" && e.shiftKey && ref_history.value.canRedo) {
					ref_history.value.redo();
				}
			}
		});

	function setup_undo_redo() {
		ref_history.value = useManualRefHistory(workflow, { clone: true });
		undo_redo_keyboard_event();
	}

	return {
		workflow_name,
		workflow_pg,
		workflow_pg_fields,
		workflow,
		workflowfields,
		statefields,
		transitionfields,
		ref_history,
		fetch,
		reset_changes,
		save_changes,
		setup_undo_redo,
	};
});
