import * as Blockly from 'blockly';
import { pythonGenerator } from 'blockly/python';
import { arduinoGenerator } from '../generators/arduino.js';
import {
  registerAddonCategories,
  clearAddonCategories,
  getAddonCategories,
  getDeviceId,
  registerDevice,
} from '../devices/registry.js';

const STORAGE_KEY = 'esp32block_addons';

/** { name: string, source: string }[] — persisted addon scripts */
function loadSavedAddons() {
  try {
    return JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
  } catch { return []; }
}

function saveAddonList(list) {
  localStorage.setItem(STORAGE_KEY, JSON.stringify(list));
}

export function getInstalledAddons() {
  return loadSavedAddons();
}

/**
 * The API object passed to every addon's init().
 * refreshToolbox / refreshDeviceList are injected later by set*Callback().
 */
let refreshToolboxFn = () => {};
let refreshDeviceListFn = () => {};

export function setRefreshCallback(fn) {
  refreshToolboxFn = fn;
}

export function setDeviceListRefreshCallback(fn) {
  refreshDeviceListFn = fn;
}

function makeAddonApi() {
  return {
    Blockly,
    pythonGenerator,
    arduinoGenerator,
    getDeviceId,
    registerCategories(categories) {
      registerAddonCategories(categories);
      refreshToolboxFn();
    },
    registerDevice(profile) {
      registerDevice(profile);
      refreshDeviceListFn();
      refreshToolboxFn();
    },
  };
}

/**
 * Execute an addon script string in the current page.
 * The script should be a self-contained function body or ES module-style code
 * that calls `init(api)` where api is the addon API.
 *
 * We wrap the source in a function that receives the api object.
 */
function runAddonSource(source) {
  const fn = new Function('api', source);
  fn(makeAddonApi());
}

/** Load a single addon from its source string. */
export function loadAddonFromSource(name, source) {
  runAddonSource(source);
}

/** Add an addon from a File object, persist it, and run it. */
export async function installAddonFromFile(file) {
  const source = await file.text();
  const name = file.name.replace(/\.js$/i, '');

  const list = loadSavedAddons();
  const existing = list.findIndex(a => a.name === name);
  if (existing >= 0) list.splice(existing, 1);
  list.push({ name, source });
  saveAddonList(list);

  loadAddonFromSource(name, source);
  return name;
}

/** Remove an addon by name. Requires page reload to fully take effect. */
export function removeAddon(name) {
  const list = loadSavedAddons().filter(a => a.name !== name);
  saveAddonList(list);
}

/** Run all persisted addons (call once at startup). */
export function loadAllSavedAddons() {
  clearAddonCategories();
  const list = loadSavedAddons();
  for (const addon of list) {
    try {
      loadAddonFromSource(addon.name, addon.source);
    } catch (err) {
      console.error(`[addon] Failed to load "${addon.name}":`, err);
    }
  }
}
