const CompanySettingsRepository = require('../../repositories/settings/CompanySettingsRepository');
const { logger } = require('../../middleware/logger');

const repo = new CompanySettingsRepository();
const ALLOWED_LOGO_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/webp', 'image/svg+xml']);
const MAX_LOGO_BYTES = 1024 * 1024;

function normalizeBase64ImageInput(rawValue, rawMimeType) {
  if (rawValue === undefined && rawMimeType === undefined) {
    return { provided: false };
  }

  if (rawValue === null || rawValue === '') {
    return { provided: true, base64: null, mimeType: null };
  }

  if (typeof rawValue !== 'string') {
    throw new Error('company_logo_base64 must be a string or null');
  }

  let value = rawValue.trim();
  let mimeType = typeof rawMimeType === 'string' ? rawMimeType.trim() : '';

  if (!value) {
    return { provided: true, base64: null, mimeType: null };
  }

  const dataUriMatch = value.match(/^data:(image\/[a-zA-Z0-9.+-]+);base64,([A-Za-z0-9+/=\r\n]+)$/);
  if (dataUriMatch) {
    mimeType = dataUriMatch[1];
    value = dataUriMatch[2];
  }

  const compactBase64 = value.replace(/\s+/g, '');
  if (!mimeType) {
    throw new Error('company_logo_mime_type is required when company_logo_base64 is provided');
  }

  if (!ALLOWED_LOGO_MIME_TYPES.has(mimeType)) {
    throw new Error(`Unsupported company logo type '${mimeType}'`);
  }

  if (!/^[A-Za-z0-9+/=]+$/.test(compactBase64)) {
    throw new Error('company_logo_base64 is not valid base64');
  }

  const bytes = Buffer.from(compactBase64, 'base64').length;
  if (bytes > MAX_LOGO_BYTES) {
    throw new Error('Company logo exceeds 1 MB');
  }

  return {
    provided: true,
    base64: compactBase64,
    mimeType,
  };
}

class CompanySettingsController {
  static async get(req, res) {
    try {
      const settings = await repo.get();
      return res.json(settings || {
        company_name: '',
        company_street: '',
        company_postal_city: '',
        company_country: '',
        company_logo_base64: null,
        company_logo_mime_type: null,
      });
    } catch (err) {
      return res.status(500).json({ message: 'Failed to load company settings' });
    }
  }

  static async update(req, res) {
    try {
      const body = req.body || {};

      const requestId = req.id;

      const contentType = (req.get('content-type') || '').toLowerCase();
      const contentLength = req.get('content-length') || null;
      if (contentType.includes('multipart/form-data')) {
        logger.warn('companySettings:update:multipart_not_supported', {
          requestId,
          contentType: req.get('content-type') || null,
          hint: 'Send JSON (application/json) or add multer middleware for this route.'
        });
      }
      if (Object.keys(body).length === 0 && contentLength && Number(contentLength) > 0) {
        logger.warn('companySettings:update:empty_parsed_body', {
          requestId,
          contentType: req.get('content-type') || null,
          contentLength,
          hint: 'Body parser may not match the request content-type or size limit.'
        });
      }

      // Accept both snake_case and camelCase
      const payload = {
        company_name: body.company_name ?? body.companyName,
        company_street: body.company_street ?? body.companyStreet,
        company_postal_city: body.company_postal_city ?? body.companyPostalCity,
        company_country: body.company_country ?? body.companyCountry,
      };
      const normalizedLogo = normalizeBase64ImageInput(
        body.company_logo_base64 ?? body.companyLogoBase64,
        body.company_logo_mime_type ?? body.companyLogoMimeType,
      );
      if (normalizedLogo.provided) {
        payload.company_logo_base64 = normalizedLogo.base64;
        payload.company_logo_mime_type = normalizedLogo.mimeType;
      }

      // Only forward keys that were actually provided (so we don't wipe values on partial updates)
      const provided = {};
      for (const [key, value] of Object.entries(payload)) {
        if (value !== undefined) provided[key] = value;
      }

      const updated = await repo.update(provided);

      return res.json(updated);
    } catch (err) {
      logger.error('companySettings:update:failed', {
        requestId: req && req.id,
        message: err?.message,
        stack: err?.stack,
      });
      return res.status(500).json({ message: 'Failed to update company settings' });
    }
  }
}

module.exports = CompanySettingsController;
