const { S3Client, PutObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
const AffiliateService = require('../../services/affiliate/AffiliateService');
const { logger } = require('../../middleware/logger');

function buildLogoUrlFromKey(key) {
  const endpoint = process.env.EXOSCALE_ENDPOINT || '';
  const bucket = process.env.EXOSCALE_BUCKET || '';
  // If using S3-compatible endpoint with virtual-hosted-style, construct URL accordingly
  if (endpoint.startsWith('http')) {
    return `${endpoint.replace(/\/$/, '')}/${bucket}/${key}`;
  }
  return key; // fallback: store key only
}

exports.list = async (req, res) => {
  try {
    const rows = await AffiliateService.list();
    const items = (rows || []).map(r => ({
      ...r,
      logoUrl: r.object_storage_id ? buildLogoUrlFromKey(r.object_storage_id) : ''
    }));
    res.json({ success: true, data: items });
  } catch (e) {
    logger.error('[AffiliateController.list] error', { msg: e.message });
    res.status(500).json({ error: 'Failed to load affiliates' });
  }
};

exports.listActive = async (req, res) => {
  try {
    const rows = await AffiliateService.list();
    const activeItems = (rows || []).filter(r => r.is_active).map(r => ({
      id: r.id,
      name: r.name,
      description: r.description,
      url: r.url,
      category: r.category,
      commission_rate: r.commission_rate,
      logoUrl: r.object_storage_id ? buildLogoUrlFromKey(r.object_storage_id) : ''
    }));
    res.json({ success: true, data: activeItems });
  } catch (e) {
    logger.error('[AffiliateController.listActive] error', { msg: e.message });
    res.status(500).json({ error: 'Failed to load affiliates' });
  }
};

exports.create = async (req, res) => {
  try {
    const { name, description, url, category, is_active, commission_rate } = req.body;

    // Validate required fields
    if (!name || !url || !category) {
      return res.status(400).json({ error: 'Missing required fields: name, url, and category are required' });
    }

    // If file uploaded, push to Exoscale and set object_storage_id
    let object_storage_id = null;
    let original_filename = null;
    let uploadedKey = null;
    if (req.file) {
      const allowedMime = ['image/jpeg','image/png','image/webp','image/svg+xml'];
      if (!allowedMime.includes(req.file.mimetype)) {
        return res.status(400).json({ error: 'Invalid image type. Allowed: JPG, PNG, WebP, SVG' });
      }
      const maxBytes = 5 * 1024 * 1024; // 5MB
      if (req.file.size > maxBytes) {
        return res.status(400).json({ error: 'Image exceeds 5MB limit' });
      }
      const s3 = new S3Client({
        region: process.env.EXOSCALE_REGION,
        endpoint: process.env.EXOSCALE_ENDPOINT,
        credentials: {
          accessKeyId: process.env.EXOSCALE_ACCESS_KEY,
          secretAccessKey: process.env.EXOSCALE_SECRET_KEY,
        },
      });
      const key = `affiliates/${Date.now()}_${req.file.originalname}`;
      await s3.send(new PutObjectCommand({
        Bucket: process.env.EXOSCALE_BUCKET,
        Key: key,
        Body: req.file.buffer,
        ContentType: req.file.mimetype,
        ACL: 'public-read'
      }));
      object_storage_id = key;
      original_filename = req.file.originalname;
      uploadedKey = key;
      logger.info('[AffiliateController.create] uploaded logo', { key });
    }

    const created = await AffiliateService.create({
      name,
      description,
      url,
      category,
      is_active: is_active !== undefined ? (is_active === 'true' || is_active === true) : true,
      commission_rate: commission_rate || null,
      object_storage_id,
      original_filename,
    });
    res.status(201).json({
      ...created,
      logoUrl: created.object_storage_id ? buildLogoUrlFromKey(created.object_storage_id) : ''
    });
  } catch (e) {
    logger.error('[AffiliateController.create] error', { msg: e.message, stack: e.stack?.split('\n')[0] });
    // best-effort cleanup of uploaded object on failure
    try {
      if (object_storage_id) {
        const s3 = new S3Client({
          region: process.env.EXOSCALE_REGION,
          endpoint: process.env.EXOSCALE_ENDPOINT,
          credentials: {
            accessKeyId: process.env.EXOSCALE_ACCESS_KEY,
            secretAccessKey: process.env.EXOSCALE_SECRET_KEY,
          },
        });
        await s3.send(new DeleteObjectCommand({ Bucket: process.env.EXOSCALE_BUCKET, Key: object_storage_id }));
      }
    } catch (cleanupErr) {
      logger.warn('[AffiliateController.create] cleanup failed', { msg: cleanupErr.message });
    }
    if (e.code === 'VALIDATION_ERROR') return res.status(400).json({ error: e.message, fields: e.errors });
    res.status(500).json({ error: 'Failed to create affiliate' });
  }
};

exports.update = async (req, res) => {
  try {
    const id = parseInt(req.params.id, 10);
    const { name, description, url, category, is_active, commission_rate } = req.body;
    const removeLogo = req.body.removeLogo === 'true';

    let object_storage_id;
    let original_filename;
    let uploadedKey = null;
    if (req.file) {
      const allowedMime = ['image/jpeg','image/png','image/webp','image/svg+xml'];
      if (!allowedMime.includes(req.file.mimetype)) {
        return res.status(400).json({ error: 'Invalid image type. Allowed: JPG, PNG, WebP, SVG' });
      }
      const maxBytes = 5 * 1024 * 1024; // 5MB
      if (req.file.size > maxBytes) {
        return res.status(400).json({ error: 'Image exceeds 5MB limit' });
      }
      const s3 = new S3Client({
        region: process.env.EXOSCALE_REGION,
        endpoint: process.env.EXOSCALE_ENDPOINT,
        credentials: {
          accessKeyId: process.env.EXOSCALE_ACCESS_KEY,
          secretAccessKey: process.env.EXOSCALE_SECRET_KEY,
        },
      });
      const key = `affiliates/${Date.now()}_${req.file.originalname}`;
      await s3.send(new PutObjectCommand({ 
        Bucket: process.env.EXOSCALE_BUCKET, 
        Key: key, 
        Body: req.file.buffer, 
        ContentType: req.file.mimetype, 
        ACL: 'public-read' 
      }));
      object_storage_id = key;
      original_filename = req.file.originalname;
      uploadedKey = key;
      logger.info('[AffiliateController.update] uploaded new logo', { id, key });
    }

    const current = await AffiliateService.get(id);
    if (!current) return res.status(404).json({ error: 'Not found' });

    // If removeLogo requested and no new file uploaded, clear existing object_storage_id
    if (removeLogo && !object_storage_id) {
      object_storage_id = null;
      original_filename = null;
      // Delete previous object if exists
      if (current && current.object_storage_id) {
        try {
          const s3del = new S3Client({
            region: process.env.EXOSCALE_REGION,
            endpoint: process.env.EXOSCALE_ENDPOINT,
            credentials: {
              accessKeyId: process.env.EXOSCALE_ACCESS_KEY,
              secretAccessKey: process.env.EXOSCALE_SECRET_KEY,
            },
          });
          await s3del.send(new DeleteObjectCommand({ Bucket: process.env.EXOSCALE_BUCKET, Key: current.object_storage_id }));
          logger.info('[AffiliateController.update] removed existing logo', { id });
        } catch (delErr) {
          logger.warn('[AffiliateController.update] remove existing logo failed', { id, msg: delErr.message });
        }
      }
    }

    const updated = await AffiliateService.update(id, {
      name: name ?? current.name,
      description: description ?? current.description,
      url: url ?? current.url,
      category: category ?? current.category,
      is_active: is_active !== undefined ? (is_active === 'true' || is_active === true) : !!current.is_active,
      commission_rate: commission_rate !== undefined ? commission_rate : current.commission_rate,
      object_storage_id: object_storage_id !== undefined ? object_storage_id : current.object_storage_id,
      original_filename: original_filename !== undefined ? original_filename : current.original_filename,
    });
    res.json({
      ...updated,
      logoUrl: updated?.object_storage_id ? buildLogoUrlFromKey(updated.object_storage_id) : ''
    });
  } catch (e) {
    logger.error('[AffiliateController.update] error', { msg: e.message });
    // best-effort cleanup of newly uploaded object on failure
    try {
      if (object_storage_id) {
        const s3 = new S3Client({
          region: process.env.EXOSCALE_REGION,
          endpoint: process.env.EXOSCALE_ENDPOINT,
          credentials: {
            accessKeyId: process.env.EXOSCALE_ACCESS_KEY,
            secretAccessKey: process.env.EXOSCALE_SECRET_KEY,
          },
        });
        await s3.send(new DeleteObjectCommand({ Bucket: process.env.EXOSCALE_BUCKET, Key: object_storage_id }));
      }
    } catch (cleanupErr) {
      logger.warn('[AffiliateController.update] cleanup failed', { msg: cleanupErr.message });
    }
    if (e.code === 'VALIDATION_ERROR') return res.status(400).json({ error: e.message, fields: e.errors });
    res.status(500).json({ error: 'Failed to update affiliate' });
  }
};

exports.updateStatus = async (req, res) => {
  try {
    const id = parseInt(req.params.id, 10);
    const { is_active } = req.body; // boolean
    const updated = await AffiliateService.updateStatus(id, !!is_active);
    res.json({
      ...updated,
      logoUrl: updated?.object_storage_id ? buildLogoUrlFromKey(updated.object_storage_id) : ''
    });
  } catch (e) {
    res.status(400).json({ error: e.message });
  }
};

exports.delete = async (req, res) => {
  try {
    const id = parseInt(req.params.id, 10);
    const current = await AffiliateService.get(id);
    if (!current) return res.status(404).json({ error: 'Not found' });

    // Delete S3 object if exists
    if (current.object_storage_id) {
      try {
        const s3 = new S3Client({
          region: process.env.EXOSCALE_REGION,
          endpoint: process.env.EXOSCALE_ENDPOINT,
          credentials: {
            accessKeyId: process.env.EXOSCALE_ACCESS_KEY,
            secretAccessKey: process.env.EXOSCALE_SECRET_KEY,
          },
        });
        await s3.send(new DeleteObjectCommand({ Bucket: process.env.EXOSCALE_BUCKET, Key: current.object_storage_id }));
        logger.info('[AffiliateController.delete] deleted logo', { id, key: current.object_storage_id });
      } catch (delErr) {
        logger.warn('[AffiliateController.delete] delete logo failed', { id, msg: delErr.message });
      }
    }

    await AffiliateService.delete(id);
    res.json({ message: 'Affiliate deleted successfully' });
  } catch (e) {
    logger.error('[AffiliateController.delete] error', { msg: e.message });
    res.status(500).json({ error: 'Failed to delete affiliate' });
  }
};
