const LAYOUT_KEY = "ioc-ui-widgets-layout";
const MIN_WIDTH = 2;
const MIN_HEIGHT = 12;

export class WidgetManager {
  constructor(gridElement, hooks = {}) {
    this.gridElement = gridElement;
    this.grid = null;
    this.templates = new Map();
    this.layout = [];
    this.hidden = [];
    this.sequence = 0;
    this.hooks = {
      onWidgetAdded: hooks.onWidgetAdded || null,
      onWidgetRemoved: hooks.onWidgetRemoved || null,
    };
  }

  registerTemplate(template) {
    this.templates.set(template.typeId, template);
  }

  initGrid() {
    this.grid = GridStack.init(
      {
        column: 12,
        cellHeight: 20,
        margin: 2,
        float: true,
        disableOneColumnMode: false,
        resizable: { handles: "se" },
        draggable: { handle: ".widget-handle" },
      },
      this.gridElement
    );

    this.loadState();
    this.pruneUnknownTemplates();
    this.ensureDefaults();
    this.renderLayout();
    this.bindPersistence();
    console.info("[UI] Сетка виджетов инициализирована", {
      layout: this.layout,
    });
  }

  ensureDefaults() {
    if (this.layout.length === 0) {
      this.layout = [
        { id: "widget-input", typeId: "input", w: 7, h: 12 },
        { id: "widget-parsed", typeId: "parsed", w: 5, h: 10 },
        { id: "widget-types", typeId: "types", w: 6, h: 10 },
        { id: "widget-history", typeId: "history", w: 5, h: 8 },
      ];
      this.hidden = [];
    }

    const hasParsed = this.layout.some((item) => item.typeId === "parsed");
    if (!hasParsed) {
      this.layout.push({
        id: `widget-parsed-${Date.now()}`,
        typeId: "parsed",
        w: 5,
        h: 5,
      });
    }
  }

  pruneUnknownTemplates() {
    const known = new Set(this.templates.keys());
    const layoutBefore = this.layout.length;
    const hiddenBefore = this.hidden.length;

    this.layout = this.layout.filter((item) => known.has(item.typeId));
    this.hidden = this.hidden.filter((typeId) => known.has(typeId));

    const removedLayout = layoutBefore - this.layout.length;
    const removedHidden = hiddenBefore - this.hidden.length;

    if (removedLayout > 0 || removedHidden > 0) {
      console.info("[UI] Удалены устаревшие шаблоны из макета", {
        removedLayout,
        removedHidden,
      });
    }
  }

  bindPersistence() {
    this.grid.on("change", () => this.persistLayout());
    this.grid.on("removed", () => this.persistLayout());
  }

  renderLayout() {
    this.layout.forEach((item) => this.renderWidget(item));
  }

  renderWidget(item) {
    const template = this.templates.get(item.typeId);
    if (!template) {
      console.warn("[UI] Не найден шаблон виджета", item.typeId);
      return;
    }

    const minWidth = template.minW || MIN_WIDTH;
    const minHeight = template.minH || MIN_HEIGHT;
    const width = Math.max(item.w || template.w || 4, minWidth);
    const height = Math.max(item.h || template.h || 3, minHeight);

    const widgetEl = document.createElement("div");
    widgetEl.dataset.typeId = item.typeId;
    widgetEl.dataset.instanceId = item.id;

    widgetEl.setAttribute("gs-w", width);
    widgetEl.setAttribute("gs-h", height);
    widgetEl.setAttribute("gs-min-w", minWidth);
    widgetEl.setAttribute("gs-min-h", minHeight);
    if (item.x !== undefined) {
      widgetEl.setAttribute("gs-x", item.x);
    }
    if (item.y !== undefined) {
      widgetEl.setAttribute("gs-y", item.y);
    }

    const card = document.createElement("div");
    card.className = "grid-stack-item-content card shadow-sm";

    const header = document.createElement("div");
    header.className =
      "card-header d-flex justify-content-between align-items-center widget-handle";
    header.innerHTML = `
      <div class="d-flex align-items-center gap-2">
        <i class="bi ${template.icon} text-secondary"></i>
        <span class="fw-semibold">${template.title}</span>
      </div>
      <button type="button" class="btn btn-sm btn-outline-secondary" data-action="hide">
        <i class="bi bi-eye-slash"></i>
        Скрыть
      </button>
    `;

    const body = document.createElement("div");
    body.className = "card-body";

    card.appendChild(header);
    card.appendChild(body);
    widgetEl.appendChild(card);

    this.grid.addWidget(widgetEl);

    this.bindHideAction(widgetEl, item.id);
    template.render(body, { instanceId: item.id });
  }

  bindHideAction(widgetEl, instanceId) {
    const hideButton = widgetEl.querySelector('[data-action="hide"]');
    hideButton.addEventListener("click", () => {
      this.hideWidget(instanceId);
    });
  }

  hideWidget(instanceId) {
    const node = this.grid
      .getGridItems()
      .find((element) => element.dataset.instanceId === instanceId);
    if (!node) {
      return;
    }

    const typeId = node.dataset.typeId;
    this.grid.removeWidget(node, true);
    this.layout = this.layout.filter((item) => item.id !== instanceId);
    this.hidden.push(typeId);
    this.persistLayout();
    if (this.hooks.onWidgetRemoved) {
      this.hooks.onWidgetRemoved(typeId, instanceId);
    }
    console.info("[UI] Виджет скрыт", { instanceId, typeId });
  }

  addWidget(typeId) {
    const template = this.templates.get(typeId);
    if (!template) {
      console.warn("[UI] Попытка добавить неизвестный виджет", typeId);
      return null;
    }

    const instanceId = `${typeId}-${Date.now()}-${this.sequence}`;
    this.sequence += 1;
    const item = {
      id: instanceId,
      typeId,
      w: template.w || 4,
      h: template.h || 3,
    };
    this.layout.push(item);
    this.renderWidget(item);
    this.persistLayout();
    if (this.hooks.onWidgetAdded) {
      this.hooks.onWidgetAdded(typeId, instanceId);
    }
    console.info("[UI] Добавлен новый виджет", { instanceId, typeId });
    return instanceId;
  }

  restoreHidden(typeId) {
    this.hidden = this.hidden.filter((candidate) => candidate !== typeId);
  }

  loadState() {
    const raw = localStorage.getItem(LAYOUT_KEY);
    if (!raw) {
      return;
    }

    try {
      const parsed = JSON.parse(raw);
      this.layout = parsed.layout || [];
      this.hidden = parsed.hidden || [];
      this.sequence = parsed.sequence || 0;
      console.info("[UI] Макет виджетов восстановлен из localStorage");
    } catch (error) {
      console.warn("[UI] Не удалось прочитать сохраненный макет", error);
    }
  }

  persistLayout() {
    if (!this.grid) {
      return;
    }

    const elements = Array.from(this.grid.getGridItems());
    const layout = elements.map((element) => {
      const node = element.gridstackNode;
      return {
        id: element.dataset.instanceId,
        typeId: element.dataset.typeId,
        x: node.x,
        y: node.y,
        w: node.w,
        h: node.h,
      };
    });

    const snapshot = {
      layout,
      hidden: this.hidden,
      sequence: this.sequence,
    };
    localStorage.setItem(LAYOUT_KEY, JSON.stringify(snapshot));
    console.debug("[UI] Макет сохранен", snapshot);
  }
}
