import { Plugin, WorkspaceLeaf, TFile } from "obsidian";
import StatusBarIntegration from "integrations/status-bar/status-bar";
import eventBus from "core/eventBus";
import { PluginSettingIntegration } from "./integrations/settings/pluginSettings";
import settingsService from "./core/settingsService";
import {
	BaseNoteStatusService,
	NoteStatusService,
} from "./core/noteStatusService";
import { StatusModalIntegration } from "./integrations/modals/statusModalIntegration";
import ContextMenuIntegration from "./integrations/context-menu/contextMenuIntegration";
import { FileExplorerIntegration } from "./integrations/file-explorer/file-explorer-integration";
import { CommandsIntegration } from "./integrations/commands/commandsIntegration";
import EditorToolbarIntegration from "./integrations/toolbar/editorToolbarIntegration";
import {
	GroupedStatusView,
	VIEW_TYPE_EXAMPLE,
} from "./integrations/views/grouped-status-view";
import {
	StatusDashboardView,
	VIEW_TYPE_STATUS_DASHBOARD,
} from "./integrations/views/status-dashboard-view";
import { StatusesInfoPopup } from "./integrations/popups/statusesInfoPopupIntegration";
import statusStoreManager from "./core/statusStoreManager";
import { isExperimentalFeatureEnabled } from "@/utils/experimentalFeatures";

export default class NoteStatusPlugin extends Plugin {
	private statusBarIntegration: StatusBarIntegration;
	private pluginSettingsIntegration: PluginSettingIntegration;
	private contextMenuIntegration: ContextMenuIntegration;
	private fileExplorerIntegration: FileExplorerIntegration;
	private commandsIntegration: CommandsIntegration;
	private editorToolbarIntegration: EditorToolbarIntegration;
	private experimentalRibbonShortcuts: Map<string, HTMLElement> = new Map();

	async onload() {
		BaseNoteStatusService.initialize(this.app);
		await this.loadPluginSettings();
		await statusStoreManager.initialize(this);

		// INFO: initialize all integrations
		Promise.all([
			this.loadContextMenu(),
			this.loadStatusBar(),
			this.loadFileExplorer(),
			this.loadCommands(),
			this.loadEditorToolbar(),
			this.loadEventBus(),
		]);

		this.registerView(
			VIEW_TYPE_EXAMPLE,
			(leaf) => new GroupedStatusView(leaf),
		);

		this.registerView(
			VIEW_TYPE_STATUS_DASHBOARD,
			(leaf) => new StatusDashboardView(leaf),
		);

		this.syncExperimentalFeatureShortcuts();
	}

	async onunload() {
		// Clean up all integrations
		this.statusBarIntegration?.destroy();
		this.contextMenuIntegration?.destroy();
		this.fileExplorerIntegration?.destroy();
		this.commandsIntegration?.destroy();
		this.editorToolbarIntegration?.destroy();
		this.pluginSettingsIntegration?.destroy();
		this.experimentalRibbonShortcuts.forEach((el) => el.remove());
		this.experimentalRibbonShortcuts.clear();

		// Clean up event subscriptions
		eventBus.unsubscribe(
			"triggered-open-modal",
			"main-triggered-open-modal-subscriptor",
		);
		eventBus.unsubscribe(
			"plugin-settings-changed",
			"main-status-popup-setting-subscriptor",
		);
	}

	async activateView() {
		const { workspace } = this.app;

		let leaf: WorkspaceLeaf | null = null;
		const leaves = workspace.getLeavesOfType(VIEW_TYPE_EXAMPLE);

		if (leaves.length > 0) {
			// A leaf with our view already exists, use that
			leaf = leaves[0];
		} else {
			// Our view could not be found in the workspace, create a new leaf
			// in the right sidebar for it
			leaf = workspace.getRightLeaf(false);
			if (!leaf) {
				console.error(
					"getRightLeaf return null, unable to setup the view",
				);
			} else {
				await leaf.setViewState({
					type: VIEW_TYPE_EXAMPLE,
					active: true,
				});
			}
		}

		// "Reveal" the leaf in case it is in a collapsed sidebar
		if (!leaf) {
			console.error("leaf not found, unable to activate the view");
		} else {
			workspace.revealLeaf(leaf);
		}
	}

	async activateDashboard() {
		const { workspace } = this.app;

		let leaf: WorkspaceLeaf | null = null;
		const leaves = workspace.getLeavesOfType(VIEW_TYPE_STATUS_DASHBOARD);

		if (leaves.length > 0) {
			// A leaf with our view already exists, use that
			leaf = leaves[0];
		} else {
			// Our view could not be found in the workspace, create a new leaf
			// in the right sidebar for it
			leaf = workspace.getRightLeaf(false);
			if (!leaf) {
				console.error(
					"getRightLeaf return null, unable to setup the dashboard",
				);
			} else {
				await leaf.setViewState({
					type: VIEW_TYPE_STATUS_DASHBOARD,
					active: true,
				});
			}
		}

		// "Reveal" the leaf in case it is in a collapsed sidebar
		if (!leaf) {
			console.error("leaf not found, unable to activate the dashboard");
		} else {
			workspace.revealLeaf(leaf);
		}
	}

	private syncExperimentalFeatureShortcuts(): void {
		const shortcuts = this.getExperimentalShortcuts();
		Object.entries(shortcuts).forEach(([key, config]) => {
			this.toggleExperimentalRibbon(key, config);
		});
	}

	private getExperimentalShortcuts() {
		return {
			groupedStatusView: {
				feature: "groupedStatusView" as const,
				icon: "list-tree",
				title: "Open grouped status view",
				handler: () => this.activateView(),
			},
			statusDashboard: {
				feature: "statusDashboard" as const,
				icon: "activity",
				title: "Open status dashboard",
				handler: () => this.activateDashboard(),
			},
		};
	}

	private toggleExperimentalRibbon(
		key: string,
		config: {
			feature: Parameters<typeof isExperimentalFeatureEnabled>[0];
			icon: string;
			title: string;
			handler: () => void;
		},
	): void {
		const isEnabled = isExperimentalFeatureEnabled(config.feature);
		const existingIcon = this.experimentalRibbonShortcuts.get(key);

		if (isEnabled && !existingIcon) {
			const ribbonEl = this.addRibbonIcon(
				config.icon,
				config.title,
				config.handler,
			);
			this.experimentalRibbonShortcuts.set(key, ribbonEl);
			return;
		}

		if (!isEnabled && existingIcon) {
			existingIcon.remove();
			this.experimentalRibbonShortcuts.delete(key);
		}
	}

	private async loadEventBus() {
		// Propagate to custom event bus the new active file
		this.app.workspace.on(
			"active-leaf-change",
			(leaf: WorkspaceLeaf | null) => {
				eventBus.publish("active-file-change", { leaf });
			},
		);

		// Propagate to custom event bus the manually frontmatter data
		this.registerEvent(
			this.app.metadataCache.on("changed", (file) => {
				eventBus.publish("status-changed", { file });
			}),
		);

		// Register listeners
		eventBus.subscribe(
			"triggered-open-modal",
			({ statusService }) => {
				StatusModalIntegration.open(this.app, statusService);
			},
			"main-triggered-open-modal-subscriptor",
		);

		eventBus.subscribe(
			"plugin-settings-changed",
			({ key, value }) => {
				if (key === "enableStatusOverviewPopup" && value === false) {
					StatusesInfoPopup.close();
				}
				if (
					key === "enableExperimentalFeatures" ||
					key === "enableStatusDashboard" ||
					key === "enableGroupedStatusView"
				) {
					this.syncExperimentalFeatureShortcuts();
				}
			},
			"main-status-popup-setting-subscriptor",
		);

		this.registerEvent(
			this.app.vault.on("create", async (file) => {
				if (
					file instanceof TFile &&
					file.extension === "md" &&
					settingsService.settings.defaultStatusForNewNotes
				) {
					// Wait a bit to ensure metadata is processed or templates are applied
					setTimeout(async () => {
						// Ensure file still exists
						if (!this.app.vault.getAbstractFileByPath(file.path)) {
							return;
						}

						const noteStatusService = new NoteStatusService(file);
						// Populate statuses to see if it already has any
						noteStatusService.populateStatuses();

						const groupedStatuses =
							noteStatusService.getStatusesByAllKeys();
						const hasStatuses = Object.values(groupedStatuses).some(
							(statuses) => statuses.length > 0,
						);

						if (!hasStatuses) {
							await noteStatusService.addStatus(
								settingsService.settings.tagPrefix,
								settingsService.settings
									.defaultStatusForNewNotes as string,
							);
						}
					}, 500); // Increased delay to allow more time for templates
				}
			}),
		);

		this.registerEvent(
			this.app.vault.on("rename", (file) => {
				if (file instanceof TFile) {
					eventBus.publish("status-changed", { file });
				}
			}),
		);

		this.registerEvent(
			this.app.vault.on("delete", (file) => {
				if (file instanceof TFile) {
					eventBus.publish("status-changed", { file });
				}
			}),
		);
	}

	async loadPluginSettings() {
		// INFO: Loads the settings data
		await settingsService.initialize(this);
		// INFO: Integrates the plugin settings section
		this.pluginSettingsIntegration = new PluginSettingIntegration(this);
		await this.pluginSettingsIntegration.integrate();
	}

	private async loadContextMenu() {
		this.contextMenuIntegration = new ContextMenuIntegration(this);
		await this.contextMenuIntegration.integrate();
	}
	private async loadStatusBar() {
		this.statusBarIntegration = new StatusBarIntegration(this);
		await this.statusBarIntegration.integrate();
	}
	private async loadFileExplorer() {
		this.fileExplorerIntegration = new FileExplorerIntegration(this);
		await this.fileExplorerIntegration.integrate();
	}

	private async loadCommands() {
		this.commandsIntegration = new CommandsIntegration(this);
		await this.commandsIntegration.integrate();
	}

	private async loadEditorToolbar() {
		this.editorToolbarIntegration = new EditorToolbarIntegration(this);
		await this.editorToolbarIntegration.integrate();
	}
}
