'use babel';

import { CompositeDisposable } from 'atom';
import { parse } from './parser';
import { render } from './render';

const fs = require('fs');
const path = require('path');

export default {
  subscriptions: null,
  panel: null,
  hudEl: null,
  activeEditorSub: null,

  activate() {
    this.subscriptions = new CompositeDisposable();

    this.hudEl = document.createElement('div');
    this.hudEl.classList.add('parvagues-hud');

    this.panel = atom.workspace.addTopPanel({
      item: this.hudEl,
      visible: true,
      priority: 100
    });

    // Sticky mode: when the user focuses a non-tidal pane (e.g. backlog.md),
    // keep the last loaded HUD visible instead of blanking. The HUD only
    // updates when a new .tidal editor becomes active or that editor saves.
    this._lastTidalEditor = null;
    render(this.hudEl, null, { idle: true });

    this.subscriptions.add(
      atom.workspace.observeActiveTextEditor((editor) => {
        // Defensive: editors fired by observeActiveTextEditor during
        // startup may not be fully constructed yet (no .element, getPath
        // still null, etc.). Wrap the whole flow so we never throw out
        // of an Atom subscription callback — that can corrupt Pulsar's
        // internal text-editor-component state.
        try { this._attachToEditor(editor); }
        catch (e) { /* swallow — HUD is non-essential */ }
      })
    );

    this.subscriptions.add(
      atom.commands.add('atom-workspace', {
        'parvagues-hud:toggle': () => this._toggle(),
        'parvagues-hud:refresh': () => this._refresh(),
        'parvagues-hud:toggle-groups': () => this._toggleGroups()
      })
    );

    this._showGroups = atom.config.get('pulsar-parvagues-hud.showGroups');
    this.subscriptions.add(
      atom.config.observe('pulsar-parvagues-hud.showGroups', (v) => {
        this._showGroups = v;
        this._refresh();
      })
    );

    // Load BootTidal.hs once — its global `let` block defines gMask/gMute*/gF*
    // for every track. Cached for the session; reload Pulsar window to pick
    // up edits to BootTidal.hs (rare).
    this._bootGroups = this._loadBootGroups();
  },

  _loadBootGroups() {
    const candidates = [];
    try {
      const cfg = atom.config.get('tidalcycles.bootTidalPath');
      if (cfg) candidates.push(cfg);
    } catch (e) {}
    try {
      for (const root of atom.project.getPaths()) {
        candidates.push(path.join(root, 'BootTidal.hs'));
      }
    } catch (e) {}
    const home = process.env.HOME || '';
    if (home) {
      candidates.push(path.join(home, '.config', 'tidalcycles', 'BootTidal.hs'));
      candidates.push(path.join(home, '.tidal', 'BootTidal.hs'));
    }
    for (const p of candidates) {
      try {
        if (p && fs.existsSync(p)) {
          const text = fs.readFileSync(p, 'utf8');
          const parsed = parse(text);
          return parsed.groups || {};
        }
      } catch (e) {}
    }
    return {};
  },

  deactivate() {
    if (this.activeEditorSub) {
      this.activeEditorSub.dispose();
      this.activeEditorSub = null;
    }
    if (this.subscriptions) {
      this.subscriptions.dispose();
      this.subscriptions = null;
    }
    if (this.panel) {
      this.panel.destroy();
      this.panel = null;
    }
    this.hudEl = null;
  },

  _isTidalFile(editor) {
    try {
      if (!editor || typeof editor.getPath !== 'function') return false;
      const path = editor.getPath();
      const ext = atom.config.get('pulsar-parvagues-hud.filenameGlob') || '.tidal';
      return !!(path && path.endsWith(ext));
    } catch (e) { return false; }
  },

  _parseSafely(text) {
    try {
      return parse(text);
    } catch (e) {
      return { groups: {}, orbits: [], errors: [`parser threw: ${e.message}`] };
    }
  },

  _attachToEditor(editor) {
    if (this.activeEditorSub) {
      this.activeEditorSub.dispose();
      this.activeEditorSub = null;
    }
    this._currentEditor = editor;

    if (!this._isTidalFile(editor)) {
      // Sticky: don't blank the HUD. Keep whatever was last loaded.
      return;
    }

    this._lastTidalEditor = editor;
    this._refresh();

    try {
      const sub = editor.onDidSave(() => {
        try { this._refresh(); } catch (e) { /* HUD must never crash editor */ }
      });
      this.activeEditorSub = sub;
      this.subscriptions.add(sub);
    } catch (e) {
      // Editor was disposed or not yet ready — skip the save subscription.
    }
  },

  _refresh() {
    if (!this.hudEl) return;
    // Prefer the active tidal editor; fall back to the last one we saw so
    // a manual refresh from a non-tidal pane still re-parses the HUD's content.
    const editor = this._isTidalFile(this._currentEditor)
      ? this._currentEditor
      : this._lastTidalEditor;
    if (!editor) {
      render(this.hudEl, null, { idle: true });
      return;
    }
    const state = this._parseSafely(editor.getText());
    // Merge BootTidal.hs groups as baseline; per-track overrides win.
    const mergedGroups = { ...(this._bootGroups || {}), ...(state.groups || {}) };
    render(this.hudEl, { ...state, groups: mergedGroups }, { showGroups: this._showGroups });
  },

  _toggle() {
    if (!this.panel) return;
    if (this.panel.isVisible()) this.panel.hide();
    else this.panel.show();
  },

  _toggleGroups() {
    this._showGroups = !this._showGroups;
    atom.config.set('pulsar-parvagues-hud.showGroups', this._showGroups);
    this._refresh();
  }
};
