import { esp32s3 } from './esp32s3.js';
import { microbit } from './microbit.js';
import { rp2040 } from './rp2040.js';
import { arduinoUno } from './arduino_uno.js';
import { builtinCategories } from '../blocks/categories/builtins.js';

const devices = {};

function register(profile) {
  devices[profile.id] = profile;
}

register(esp32s3);
register(microbit);
register(rp2040);
register(arduinoUno);

/**
 * Register a new device at runtime (e.g. a sub-device like "ESP32 robot").
 * Call refreshToolbox() in main.js after registering to pick up changes.
 */
export function registerDevice(profile) {
  register(profile);
}

export function getDeviceIds() {
  return Object.keys(devices);
}

export function getDeviceProfile(id) {
  return devices[id] || null;
}

export function getAllDevices() {
  return { ...devices };
}

// --- active device state ---

const STORAGE_KEY = 'esp32block_device';

let currentId = localStorage.getItem(STORAGE_KEY) || 'esp32s3';
if (!devices[currentId]) currentId = 'esp32s3';

export function getDeviceId() {
  return currentId;
}

export function getDevice() {
  return devices[currentId];
}

export function setDeviceId(id) {
  if (!devices[id]) return;
  currentId = id;
  localStorage.setItem(STORAGE_KEY, id);
}

export function canFlashInBrowser() {
  return getDevice().firmware?.canFlashInBrowser === true;
}

// --- toolbox builder ---

const addonCategories = [];

export function registerAddonCategories(categories) {
  for (const cat of categories) {
    if (cat && cat.kind === 'category') addonCategories.push(cat);
  }
}

export function getAddonCategories() {
  return addonCategories;
}

export function clearAddonCategories() {
  addonCategories.length = 0;
}

/**
 * Returns the full unfiltered category list for a device (for the customizer UI).
 */
export function getFullCategories(deviceId) {
  const profile = devices[deviceId || currentId];
  if (!profile) return [];
  const contents = [...profile.categories];
  if (addonCategories.length) {
    contents.push(...addonCategories);
  }
  contents.push(...builtinCategories);
  return contents.filter(c => c.kind === 'category');
}

// --- toolbox filter (show/hide categories & blocks) ---

const FILTER_KEY = 'esp32block_toolbox_filter';
const PRESETS_KEY = 'esp32block_toolbox_presets';

let _customizeMode = false;

export function setCustomizeMode(on) { _customizeMode = on; }
export function isCustomizeMode() { return _customizeMode; }

export function getFilter(deviceId) {
  try {
    const data = JSON.parse(localStorage.getItem(FILTER_KEY)) || {};
    return data[deviceId || currentId] || {};
  } catch { return {}; }
}

export function setFilter(deviceId, filter) {
  let data;
  try { data = JSON.parse(localStorage.getItem(FILTER_KEY)) || {}; }
  catch { data = {}; }
  data[deviceId || currentId] = filter;
  localStorage.setItem(FILTER_KEY, JSON.stringify(data));
}

// --- presets ---

const BUILTIN_PRESETS = [
  {
    name: 'Legobot',
    builtin: true,
    filter: {
      hiddenCategories: [
        'Pin I/O', 'PWM', 'ADC', 'WiFi', 'NeoPixel', 'I2C',
        'HID (Keyboard / Mouse / Gamepad)',
      ],
      hiddenBlocks: [
        'sound_play_tone', 'sound_play_note', 'sound_play_staff_note',
        'sound_stop', 'hbridge_motor_init', 'hbridge_motor_speed',
        'hbridge_motor_stop',
      ],
    },
  },
  {
    name: 'Show All',
    builtin: true,
    filter: { hiddenCategories: [], hiddenBlocks: [] },
  },
];

function getUserPresets() {
  try { return JSON.parse(localStorage.getItem(PRESETS_KEY)) || []; }
  catch { return []; }
}

export function getSavedPresets() {
  return [...BUILTIN_PRESETS, ...getUserPresets()];
}

export function savePreset(name, filter) {
  if (BUILTIN_PRESETS.some(p => p.name === name)) return;
  const presets = getUserPresets();
  const idx = presets.findIndex(p => p.name === name);
  if (idx >= 0) presets[idx] = { name, filter };
  else presets.push({ name, filter });
  localStorage.setItem(PRESETS_KEY, JSON.stringify(presets));
}

export function deletePreset(name) {
  if (BUILTIN_PRESETS.some(p => p.name === name)) return;
  const presets = getUserPresets().filter(p => p.name !== name);
  localStorage.setItem(PRESETS_KEY, JSON.stringify(presets));
}

// --- filter application ---

function applyFilter(categories, deviceId) {
  const filter = getFilter(deviceId);
  const hidCats = new Set(filter.hiddenCategories || []);
  const hidBlocks = new Set(filter.hiddenBlocks || []);
  if (!hidCats.size && !hidBlocks.size) return categories;

  const result = [];
  for (const item of categories) {
    if (item.kind === 'sep') { result.push(item); continue; }
    if (item.kind === 'category' && hidCats.has(item.name)) continue;
    if (item.kind === 'category' && item.contents) {
      const filtered = item.contents.filter(b => !hidBlocks.has(b.type));
      if (filtered.length === 0) continue;
      result.push({ ...item, contents: filtered });
    } else {
      result.push(item);
    }
  }
  return result.filter((item, i, arr) => {
    if (item.kind !== 'sep') return true;
    if (i === 0 || i === arr.length - 1) return false;
    return arr[i - 1]?.kind !== 'sep';
  });
}

export function buildToolbox(deviceId) {
  const id = deviceId || currentId;
  const profile = devices[id];
  if (!profile) return { kind: 'categoryToolbox', contents: [] };

  const contents = [...profile.categories];
  if (addonCategories.length) {
    contents.push({ kind: 'sep' });
    contents.push(...addonCategories);
  }
  contents.push({ kind: 'sep' });
  contents.push(...builtinCategories);

  if (_customizeMode) return { kind: 'categoryToolbox', contents };
  return { kind: 'categoryToolbox', contents: applyFilter(contents, id) };
}
