import { put, del } from '../../../lib/object-storage.js';
import { sql } from '../../../lib/sql.js';
import { getUserFromRequest } from '../../../lib/permission-middleware';
import { checkUploadRateLimit } from '../../../lib/rate-limit.js';

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '2mb',
    },
  },
};

const ALLOWED_TYPES = ['image/png', 'image/webp', 'image/svg+xml'];
const CODE_RE = /^[A-Za-z0-9]{1,10}$/;

export default async function handler(req, res) {
  try {
    const user = await getUserFromRequest(req);
    if (!user) {
      return res.status(401).json({ error: 'Authentication required' });
    }

    if (req.method === 'GET') {
      const result = await sql`
        SELECT id, code, image_url, created_at
        FROM custom_symbols
        WHERE user_id = ${user.userId}
        ORDER BY code ASC
      `;
      return res.status(200).json({ symbols: result.rows });
    }

    if (req.method === 'POST') {
      const { allowed, reset } = await checkUploadRateLimit(req, user.userId);
      if (!allowed) {
        res.setHeader('Retry-After', Math.ceil((reset - Date.now()) / 1000));
        return res.status(429).json({ error: 'Too many attempts. Try again later.' });
      }

      const contentType = req.headers['content-type'];
      if (!contentType || !contentType.startsWith('multipart/form-data')) {
        return res.status(400).json({ error: 'Content-Type must be multipart/form-data' });
      }

      const formData = await parseMultipartFormData(req);
      const code = (formData.code || '').trim();
      const file = formData.image;

      if (!CODE_RE.test(code)) {
        return res.status(400).json({
          error: 'Symbol code must be 1-10 letters or numbers (e.g. F, E, 10)',
        });
      }
      if (!file) {
        return res.status(400).json({ error: 'No symbol image provided' });
      }
      if (!ALLOWED_TYPES.includes(file.type)) {
        return res.status(400).json({
          error: 'Invalid file type. Please upload a PNG, WebP, or SVG image.',
        });
      }
      if (file.size > 2 * 1024 * 1024) {
        return res.status(400).json({ error: 'File size must be less than 2MB' });
      }

      // Replace any existing symbol with the same code.
      const existing = await sql`
        SELECT id, image_url FROM custom_symbols
        WHERE user_id = ${user.userId} AND code = ${code}
      `;
      if (existing.rows.length > 0) {
        try {
          await del(existing.rows[0].image_url);
        } catch (blobError) {
          console.warn('Failed to delete old symbol image:', blobError);
        }
      }

      const ext = file.type === 'image/svg+xml' ? 'svg' : file.type.split('/')[1];
      const filename = `symbols/${user.userId}-${code.toLowerCase()}-${Date.now()}.${ext}`;
      const blob = await put(filename, file.buffer, {
        access: 'public',
        contentType: file.type,
      });

      const saved = await sql`
        INSERT INTO custom_symbols (user_id, code, image_url)
        VALUES (${user.userId}, ${code}, ${blob.url})
        ON CONFLICT (user_id, code)
        DO UPDATE SET image_url = ${blob.url}, created_at = CURRENT_TIMESTAMP
        RETURNING id, code, image_url, created_at
      `;

      return res.status(existing.rows.length > 0 ? 200 : 201).json({ symbol: saved.rows[0] });
    }

    return res.status(405).json({ error: 'Method not allowed' });
  } catch (error) {
    console.error('Custom symbols API error:', error);
    return res.status(500).json({ error: 'Internal server error' });
  }
}

async function parseMultipartFormData(req) {
  return new Promise((resolve, reject) => {
    const chunks = [];

    req.on('data', (chunk) => {
      chunks.push(chunk);
    });

    req.on('end', () => {
      try {
        const buffer = Buffer.concat(chunks);
        const boundary = req.headers['content-type'].split('boundary=')[1];
        const parts = buffer.toString('binary').split(`--${boundary}`);

        const formData = {};

        for (const part of parts) {
          if (part.includes('Content-Disposition: form-data')) {
            const nameMatch = part.match(/name="([^"]+)"/);
            const filenameMatch = part.match(/filename="([^"]+)"/);
            const contentTypeMatch = part.match(/Content-Type: ([^\r\n]+)/);

            if (nameMatch) {
              const fieldName = nameMatch[1];
              const headerEndIndex = part.indexOf('\r\n\r\n');

              if (headerEndIndex !== -1) {
                const content = part.substring(headerEndIndex + 4);
                const contentBuffer = Buffer.from(content, 'binary');

                if (filenameMatch && contentTypeMatch) {
                  formData[fieldName] = {
                    originalName: filenameMatch[1],
                    type: contentTypeMatch[1].trim(),
                    buffer: contentBuffer.slice(0, -2),
                    size: contentBuffer.length - 2,
                  };
                } else {
                  formData[fieldName] = content.trim();
                }
              }
            }
          }
        }

        resolve(formData);
      } catch (error) {
        reject(error);
      }
    });

    req.on('error', reject);
  });
}
