const express = require('express');
const fsp = require('fs').promises;
const path = require('path');
const { LIMITS } = require('../../src/utilities/constants');
const { exists } = require('../../src/utilities/fs-helpers');
const { ValidationError } = require('../../src/utilities/errors');
const platformPaths = require('../../platform-paths');
const { ok, successMessage } = require('../../src/utils/responses');
/**
 * Config assets routes factory
 * @param {Object} deps - Explicit dependencies
 * @param {Object} deps.servicesStateManager - Services state manager
 * @param {Function} deps.asyncHandler - Async route handler wrapper
 * @param {Object} deps.log - Logger instance
 * @returns {express.Router}
 */

// Image processing for favicon conversion (optional)
let sharp, pngToIco;
try {
  sharp = require('sharp');
  pngToIco = require('png-to-ico');
} catch (e) {
  // Image processing libraries not available — favicon conversion disabled
}

module.exports = function({ servicesStateManager: _servicesStateManager, asyncHandler, log: _log, CONFIG_FILE, readConfig, saveConfig, errorResponse }) {
  const router = express.Router();
  const ctx = { CONFIG_FILE, readConfig, saveConfig, errorResponse };

  // ===== ASSET UPLOAD =====

  router.post('/assets/upload', express.json({ limit: LIMITS.BODY_UPLOAD }), asyncHandler(async (req, res) => {
    const { filename, data } = req.body;

    if (!filename || !data) {
      throw new ValidationError('filename and data are required');
    }

    // Validate filename to prevent directory traversal
    const safeFilename = path.basename(filename);
    if (safeFilename !== filename || filename.includes('..')) {
      throw new ValidationError('Invalid filename - must not contain path separators');
    }

    // Extract base64 data
    const matches = data.match(/^data:image\/([a-zA-Z+]+);base64,(.+)$/);
    if (!matches) {
      throw new ValidationError('Invalid image data format');
    }

    const base64Data = matches[2];
    const buffer = Buffer.from(base64Data, 'base64');

    // Determine assets path (mounted volume)
    const assetsPath = platformPaths.resolveAssetsPath(process.env.ASSETS_PATH);

    // Ensure directory exists
    if (!await exists(assetsPath)) {
      await fsp.mkdir(assetsPath, { recursive: true });
    }

    // Save file
    const filePath = path.join(assetsPath, safeFilename);
    await fsp.writeFile(filePath, buffer);

    ok(res, {
      path: `/assets/${safeFilename}`,
      message: `Logo saved to ${filePath}`
    });
  }, 'assets-upload'));

  // ===== CUSTOM LOGO ENDPOINTS =====
  // Manage custom dashboard logo

  // Get current logo path, position, and title
  router.get('/logo', asyncHandler(async (req, res) => {
    const config = await ctx.readConfig();
    ok(res, {
      // Dark/light variants (new)
      customLogoDark: config.customLogoDark || null,
      customLogoLight: config.customLogoLight || null,
      // Legacy single-logo fallback
      customLogo: config.customLogo || config.customLogoDark || null,
      position: config.logoPosition || 'left',
      dashboardTitle: config.dashboardTitle || 'DashCaddy',
      isDefault: !config.customLogoDark && !config.customLogoLight && !config.customLogo
    });
  }, 'logo-get'));

  // Helper: save a base64 image to assets, return { filename, webPath }
  async function saveLogoFile(data, suffix) {
    const matches = data.match(/^data:image\/([a-zA-Z+]+);base64,(.+)$/);
    if (!matches) return null;

    const extension = matches[1] === 'svg+xml' ? 'svg' : matches[1];
    const buffer = Buffer.from(matches[2], 'base64');

    const assetsPath = platformPaths.resolveAssetsPath(process.env.ASSETS_PATH);
    if (!await exists(assetsPath)) {
      await fsp.mkdir(assetsPath, { recursive: true });
    }

    const filename = `custom-logo-${suffix}.${extension}`;
    await fsp.writeFile(`${assetsPath}/${filename}`, buffer);
    return `/assets/${filename}`;
  }

  // Upload custom logo(s) and/or update position and title
  // Supports: dataDark/dataLight (separate variants) or data (single logo for both)
  // eslint-disable-next-line complexity
  router.post('/logo', express.json({ limit: LIMITS.BODY_UPLOAD }), asyncHandler(async (req, res) => {
    const { data, dataDark, dataLight, position, dashboardTitle } = req.body;

    if (!data && !dataDark && !dataLight && !position && !dashboardTitle) {
      throw new ValidationError('Image data, position, or title is required');
    }

    const config = await ctx.readConfig();
    let pathDark = null, pathLight = null;

    // New dual-variant upload
    if (dataDark) {
      pathDark = await saveLogoFile(dataDark, 'dark');
      if (!pathDark) throw new ValidationError('Invalid dark logo data format');
      config.customLogoDark = pathDark;
    }
    if (dataLight) {
      pathLight = await saveLogoFile(dataLight, 'light');
      if (!pathLight) throw new ValidationError('Invalid light logo data format');
      config.customLogoLight = pathLight;
    }

    // Legacy single-logo: save as both variants
    if (data && !dataDark && !dataLight) {
      const singlePath = await saveLogoFile(data, 'dark');
      if (!singlePath) throw new ValidationError('Invalid image data format');
      config.customLogoDark = singlePath;
      config.customLogoLight = singlePath;
      // Also set legacy field for backward compat
      config.customLogo = singlePath;
      pathDark = singlePath;
      pathLight = singlePath;
    }

    if (position && ['left', 'center', 'right'].includes(position)) {
      config.logoPosition = position;
    }

    if (dashboardTitle !== undefined) {
      const sanitizedTitle = String(dashboardTitle).trim().substring(0, 50);
      config.dashboardTitle = sanitizedTitle || 'DashCaddy';
    }

    config.updatedAt = new Date().toISOString();
    await fsp.writeFile(ctx.CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');

    ok(res, {
      pathDark: pathDark,
      pathLight: pathLight,
      // Legacy compat
      path: pathDark || pathLight,
      position: config.logoPosition || 'left',
      dashboardTitle: config.dashboardTitle || 'DashCaddy',
      message: 'Branding settings saved'
    });
  }, 'logo-upload'));

  // Reset all branding to defaults
  router.delete('/logo', asyncHandler(async (req, res) => {
    const config = await ctx.readConfig();
    const assetsPath = platformPaths.resolveAssetsPath(process.env.ASSETS_PATH);

    // Delete all custom logo files
    const logoPaths = [config.customLogo, config.customLogoDark, config.customLogoLight].filter(Boolean);
    const seen = new Set();
    for (const logoPath of logoPaths) {
      const filename = path.basename(logoPath);
      if (!filename || seen.has(filename)) continue;
      seen.add(filename);
      const filePath = path.join(assetsPath, filename);
      if (await exists(filePath)) {
        await fsp.unlink(filePath);
      }
    }

    // Reset all branding settings to defaults
    delete config.customLogo;
    delete config.customLogoDark;
    delete config.customLogoLight;
    delete config.dashboardTitle;
    delete config.logoPosition;
    config.updatedAt = new Date().toISOString();
    await fsp.writeFile(ctx.CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');

    successMessage(res, 'Branding reset to defaults');
  }, 'logo-delete'));

  // ===== FAVICON ENDPOINTS =====
  // Upload and convert favicon (PNG/SVG to ICO)

  // Get current favicon
  router.get('/favicon', asyncHandler(async (req, res) => {
    const config = await ctx.readConfig();
    ok(res, {
      customFavicon: config.customFavicon || null,
      isDefault: !config.customFavicon
    });
  }, 'favicon-get'));

  // Upload and convert favicon
  router.post('/favicon', asyncHandler(async (req, res) => {
    const { data } = req.body;

    if (!data) {
      throw new ValidationError('Image data is required');
    }

    if (!sharp || !pngToIco) {
      return ctx.errorResponse(res, 500, 'Image processing not available');
    }

    // Extract base64 data
    const matches = data.match(/^data:image\/([a-zA-Z+]+);base64,(.+)$/);
    if (!matches) {
      throw new ValidationError('Invalid image data format');
    }

    const base64Data = matches[2];
    const buffer = Buffer.from(base64Data, 'base64');

    const assetsPath = platformPaths.resolveAssetsPath(process.env.ASSETS_PATH);
    if (!await exists(assetsPath)) {
      await fsp.mkdir(assetsPath, { recursive: true });
    }

    // Convert to PNG at multiple sizes for ICO
    const sizes = [16, 32, 48];
    const pngBuffers = await Promise.all(
      sizes.map(size =>
        sharp(buffer)
          .resize(size, size, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
          .png()
          .toBuffer()
      )
    );

    // Convert to ICO
    const icoBuffer = await pngToIco(pngBuffers);

    // Save ICO file
    const icoPath = `${assetsPath}/favicon.ico`;
    await fsp.writeFile(icoPath, icoBuffer);

    // Also save a PNG version for modern browsers
    const png32 = await sharp(buffer)
      .resize(32, 32, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
      .png()
      .toBuffer();
    await fsp.writeFile(`${assetsPath}/favicon.png`, png32);

    // Update config
    await ctx.saveConfig({ customFavicon: '/assets/favicon.ico', updatedAt: new Date().toISOString() });

    ok(res, {
      path: '/assets/favicon.ico',
      message: 'Favicon created successfully'
    });
  }, 'favicon'));

  // Reset favicon to default
  router.delete('/favicon', asyncHandler(async (req, res) => {
    const config = await ctx.readConfig();

    // Delete custom favicon files
    const assetsPath = platformPaths.resolveAssetsPath(process.env.ASSETS_PATH);
    const filesToDelete = ['favicon.ico', 'favicon.png'];
    for (const file of filesToDelete) {
      const filePath = `${assetsPath}/${file}`;
      if (await exists(filePath)) {
        await fsp.unlink(filePath);
      }
    }

    delete config.customFavicon;
    config.updatedAt = new Date().toISOString();
    await fsp.writeFile(ctx.CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');

    successMessage(res, 'Favicon reset to default');
  }, 'favicon-delete'));

  return router;
};
