// PRE Web GUI — Model provider routes (Ollama, OpenAI, Azure, Anthropic, llama.cpp, tinygrad)
const { Router } = require('express');
const {
  getProvider, getAllProviders, setProvider, removeProvider, testProvider,
} = require('../connections');

const router = Router();

// ── Provider selection ──

router.get('/provider', (_req, res) => {
  const store = getAllProviders();
  const masked = { active: store.active || 'ollama' };
  // Remote providers: include sub-config but mask the api_key
  for (const type of ['openai', 'azure', 'anthropic']) {
    if (store[type]) {
      masked[type] = { ...store[type] };
      if (masked[type].api_key) {
        masked[type].api_key = masked[type].api_key.slice(0, 4) + '...' + masked[type].api_key.slice(-4);
      }
    }
  }
  // Local providers: no auth to mask, include as-is so the settings form can pre-populate
  for (const type of ['tinygrad', 'llamacpp']) {
    if (store[type]) masked[type] = { ...store[type] };
  }
  masked.type = masked.active;
  res.json(masked);
});

router.post('/provider', (req, res) => {
  try {
    const config = { ...req.body };
    if (!config.api_key) {
      const saved = getProvider();
      if (saved.api_key) config.api_key = saved.api_key;
    }
    setProvider(config);
    res.json({ success: true });
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});

router.delete('/provider', (_req, res) => {
  removeProvider();
  res.json({ success: true, provider: { type: 'ollama' } });
});

router.post('/provider/test', async (req, res) => {
  try {
    const config = { ...req.body };
    if (!config.api_key) {
      const saved = getProvider();
      if (saved.api_key) config.api_key = saved.api_key;
    }
    const result = await testProvider(config);
    res.json(result);
  } catch (err) {
    res.json({ success: false, message: err.message });
  }
});

// ── llama.cpp server ──

const llamacpp = require('../llamacpp');
const llamacppModel = require('../llamacpp-model');

router.get('/llamacpp/status', async (_req, res) => {
  try {
    const status = await llamacpp.getStatus();
    res.json(status);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.post('/llamacpp/start', async (req, res) => {
  try {
    const result = await llamacpp.start(req.body);
    res.json({ success: true, ...result });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.post('/llamacpp/stop', (_req, res) => {
  llamacpp.stop();
  res.json({ success: true });
});

router.get('/llamacpp/models', (_req, res) => {
  try {
    const models = llamacppModel.listAvailableModels();
    const binaryPath = llamacpp.getBinaryPath();
    res.json({ models, binaryPath, binaryInstalled: !!binaryPath });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// ── tinygrad ──

const tinygradServer = require('../tinygrad');
const { gpuDetector } = require('../gpu-detect');

router.get('/gpu/status', (_req, res) => {
  res.json(gpuDetector.getState() || { available: false });
});

router.get('/tinygrad/status', async (_req, res) => {
  try {
    const status = await tinygradServer.getStatus();
    res.json(status);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.post('/tinygrad/start', async (req, res) => {
  try {
    // Merge with saved sub-config so manual Start picks up python_path,
    // tinygrad_path, and any other server-side fields the form doesn't post.
    const saved = getAllProviders().tinygrad || {};
    const merged = { ...saved, ...req.body };
    const result = await tinygradServer.start(merged);
    res.json({ success: true, ...result });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.post('/tinygrad/stop', (_req, res) => {
  tinygradServer.stop();
  res.json({ success: true });
});

// ── Escalation ──

const escalation = require('../escalation');

router.get('/escalation/status', async (_req, res) => {
  try {
    const cached = escalation.getLastStatus();
    const status = cached || await escalation.probe();
    res.json(status);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.post('/escalation/probe', async (_req, res) => {
  try {
    const status = await escalation.probe();
    res.json(status);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// ── Router (multi-model) ──

const routerConfig = require('../router');

router.get('/router', (_req, res) => {
  res.json(routerConfig.getConfig());
});

router.post('/router', (req, res) => {
  try {
    const config = routerConfig.saveConfig(req.body || {});
    res.json({ success: true, config });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

router.delete('/router', (_req, res) => {
  const config = routerConfig.resetConfig();
  res.json({ success: true, config });
});

router.get('/router/models', async (_req, res) => {
  try {
    const result = await new Promise((resolve, reject) => {
      const reqHttp = require('http').request({
        hostname: '127.0.0.1',
        port: parseInt(process.env.PRE_PORT || '11434', 10),
        path: '/api/tags',
        method: 'GET',
      }, (resp) => {
        let body = '';
        resp.on('data', (c) => body += c);
        resp.on('end', () => {
          try { resolve(JSON.parse(body).models || []); } catch (e) { reject(e); }
        });
      });
      reqHttp.on('error', reject);
      reqHttp.setTimeout(5000, () => { reqHttp.destroy(); reject(new Error('timeout')); });
      reqHttp.end();
    });
    const smallModels = result
      .filter(m => (m.size || 0) / 1e9 < 10 && m.name !== 'pre-gemma4' && m.name !== 'nomic-embed-text:latest')
      .map(m => ({
        name: m.name, size: m.size,
        sizeHuman: m.size < 1e9 ? `${(m.size / 1e6).toFixed(0)}MB` : `${(m.size / 1e9).toFixed(1)}GB`,
        family: m.details?.family || '', parameterSize: m.details?.parameter_size || '',
      }));
    const allModels = result
      .filter(m => m.name !== 'nomic-embed-text:latest')
      .map(m => ({
        name: m.name, size: m.size,
        sizeHuman: m.size < 1e9 ? `${(m.size / 1e6).toFixed(0)}MB` : `${(m.size / 1e9).toFixed(1)}GB`,
        family: m.details?.family || '', parameterSize: m.details?.parameter_size || '',
      }));
    res.json({ recommended: smallModels, all: allModels });
  } catch (err) {
    res.json({ recommended: [], all: [], error: err.message });
  }
});

module.exports = router;
