import { HarmonixRegionManager, IRegionManager, HarmonixViewDefinition } from "@uxland/harmonix";
import { PluginInfo } from "../../handle-plugins";
import { IRegion } from "@uxland/regions";
import { shellRegions, clinicalMonitoringRegions, activityHistoryRegions, administrativeManagementRegions } from "./regions";
import { PrimariaBroker } from "../broker/primaria-broker";
import { BROKER_EVENTS } from "../broker/broker-events";

export interface PrimariaRegionManager extends HarmonixRegionManager {
  regions: {
    shell: typeof shellRegions;
    clinicalMonitoring: typeof clinicalMonitoringRegions;
    activityHistory: typeof activityHistoryRegions;
    administrativeManagement: typeof administrativeManagementRegions;
  };
  registerQuickAction(view: HarmonixViewDefinition): Promise<void>;
  registerNavigationMenu(view: HarmonixViewDefinition): Promise<void>;
  registerMainView(view: HarmonixViewDefinition): Promise<void>;
  activateMainView(viewId: string): Promise<void>;
  activatePluginView(regionName: string, pluginId: string, viewId: string): Promise<void>;
  getCurrentMainViewActive(): string | undefined;
  _destroy(): void;
}

class RegionManagerProxy implements PrimariaRegionManager {
  regions = {
    shell: shellRegions,
    clinicalMonitoring: clinicalMonitoringRegions,
    activityHistory: activityHistoryRegions,
    administrativeManagement: administrativeManagementRegions,
  };

  constructor(
    private pluginInfo: PluginInfo,
    private regionManager: IRegionManager,
    private broker: PrimariaBroker,
  ) {}
  /**
   * Register a view in a specific region.
   *
   * @param {string} regionName - The name of the region to register the view with.
   * @param {HarmonixViewDefinition} view - The view definition to be registered.
   * @return {Promise<void>} A promise that resolves when the view is successfully registered.
   */
  async registerView(regionName: string, view: HarmonixViewDefinition): Promise<void> {
    const key = `${this.pluginInfo.pluginId}::${view.id}`;

    await this.regionManager.registerViewWithRegion(regionName, key, view);
    this.activateIfDefault(regionName, key, view);
  }
  /**
   * Removes a view from a specific region.
   *
   * @param {string} regionName - The name of the region to remove the view from.
   * @param {string} viewId - The ID of the view to be removed.
   * @return {Promise<void>} A promise that resolves when the view is successfully removed.
   */
  async removeView(regionName: string, viewId: string): Promise<void> {
    await this.regionManager.unregisterViewFromRegion(regionName, `${this.pluginInfo.pluginId}::${viewId}`);
  }
  /**
   * Activates a view in a specific region.
   *
   * @param {string} regionName - The name of the region where the view is located.
   * @param {string} viewId - The ID of the view to be activated.
   * @return {Promise<void>} A promise that resolves when the view is successfully activated.
   */
  activateView(regionName: string, viewId: string): Promise<void> {
    this.regionManager.getRegion(regionName).activate(`${this.pluginInfo.pluginId}::${viewId}`);
    if (regionName === this.regions.shell.main) this._notifyMainViewChanged(viewId);
    return Promise.resolve();
  }
  /**
   * Deactivates a view in a specific region.
   *
   * @param {string} regionName - The name of the region where the view is located.
   * @param {string} viewId - The ID of the view to be deactivated.
   * @return {Promise<void>} A promise that resolves when the view is successfully deactivated.
   */
  deactivateView(regionName: string, viewId: string): Promise<void> {
    this.regionManager.getRegion(regionName).deactivate(`${this.pluginInfo.pluginId}::${viewId}`);
    return Promise.resolve();
  }
  /**
   * Retrieves a region by its name.
   *
   * @param {string} regionName - The name of the region to retrieve.
   * @return {Promise<IRegion>} A promise that resolves to the retrieved region.
   */
  getRegion(regionName: string): Promise<IRegion> {
    return Promise.resolve(this.regionManager.getRegion(regionName));
  }
  /**
   * Checks if a view with the given ID exists in a specific region.
   *
   * @param {string} regionName - The name of the region to check.
   * @param {string} viewId - The ID of the view to check for.
   * @return {Promise<boolean>} A promise that resolves to true if the view exists, false otherwise.
   */
  containsView(regionName: string, viewId: string) {
    const region = this.regionManager.getRegion(regionName);
    return Promise.resolve(region?.containsView(`${this.pluginInfo.pluginId}::${viewId}`));
  }
  /**
   * Checks if a view with the given ID is active in a specific region.
   *
   * @param {string} regionName - The name of the region to check.
   * @param {string} viewId - The ID of the view to check for.
   * @return {Promise<boolean>} A promise that resolves to true if the view is active, false otherwise.
   */
  isViewActive(regionName: string, viewId: string) {
    const region = this.regionManager.getRegion(regionName);
    const isViewActive = region.currentActiveViews.some((view) => view.id === viewId);
    return Promise.resolve(isViewActive);
  }
  async registerQuickAction(view: HarmonixViewDefinition): Promise<void> {
    await this.regionManager.registerViewWithRegion(this.regions.shell.quickActions, `${this.pluginInfo.pluginId}::${view.id}`, view);
  }
  async registerNavigationMenu(view: HarmonixViewDefinition): Promise<void> {
    await this.regionManager.registerViewWithRegion(this.regions.shell.navigationMenu, `${this.pluginInfo.pluginId}::${view.id}`, view);
  }
  async registerMainView(view: HarmonixViewDefinition): Promise<void> {
    await this.regionManager.registerViewWithRegion(this.regions.shell.main, `${this.pluginInfo.pluginId}::${view.id}`, view);
  }
  activateMainView(viewId: string): Promise<void> {
    this.regionManager.getRegion(this.regions.shell.main).activate(`${this.pluginInfo.pluginId}::${viewId}`);
    this._notifyMainViewChanged(viewId);
    return Promise.resolve();
  }
  /**
   * Activates a view that was registered by another plugin.
   *
   * Unlike `activateView`, which always prefixes with the calling plugin's id, this method
   * lets an orchestrator activate views owned by a different plugin by passing the owner's
   * pluginId explicitly. Use only when crossing plugin boundaries.
   *
   * @param {string} regionName - The name of the region where the view is located.
   * @param {string} pluginId - The id of the plugin that registered the view.
   * @param {string} viewId - The id of the view to be activated.
   * @return {Promise<void>} A promise that resolves when the view is successfully activated.
   */
  activatePluginView(regionName: string, pluginId: string, viewId: string): Promise<void> {
    this.regionManager.getRegion(regionName).activate(`${pluginId}::${viewId}`);
    if (regionName === this.regions.shell.main) this._notifyMainViewChanged(viewId);
    return Promise.resolve();
  }

  getCurrentMainViewActive() {
    const mainView = this.regionManager.getRegion(this.regions.shell.main).currentActiveViews[0] as HarmonixViewDefinition;
    return mainView?.id;
  }

  /**
   * Activates a view if it is marked as default and the region currently has no active views.
   *
   * @param {string} regionName - The name of the region to activate the view in.
   * @param {string} key - The key of the view to activate.
   * @param {HarmonixViewDefinition} view - The view to activate.
   * @return {void}
   */
  activateIfDefault(regionName: string, key: string, view: HarmonixViewDefinition) {
    if (!(view as any).isDefault) return;

    const region = this.regionManager.getRegion(regionName);
    if (!region || typeof (region as any).activate !== "function") return;

    const hasActiveView = region.currentActiveViews?.length > 0;
    if (!hasActiveView) {
      (region as any).activate(key);
    }
  }

  _notifyMainViewChanged(viewId: string) {
    this.broker.publish(BROKER_EVENTS.shell.mainViewChanged, { viewId });
  }

  _destroy() {
    this.regionManager.destroy();
  }
}

/**
 * Creates a proxy for the region manager with the given plugin info and region manager instance.
 *
 * @param {PluginInfo} pluginInfo - The plugin information.
 * @param {IRegionManager} regionManager - The region manager instance.
 * @return {HarmonixRegionManager} The created region manager proxy.
 */
export const createRegionManagerProxy = (
  pluginInfo: PluginInfo,
  regionManager: IRegionManager,
  broker: PrimariaBroker,
): PrimariaRegionManager => new RegionManagerProxy(pluginInfo, regionManager, broker);
