Clone
import { Database } from '../lib/db';
import { generateSlug, validateCustomSlug } from '../utils/slug';
import { validateUrl, sanitizeInput } from '../utils/validation';
import { ValidationError, NotFoundError, AuthError } from '../utils/errors';

export async function apiRoutes(request, env, ctx) {
  const url = new URL(request.url);
  const path = url.pathname;
  const method = request.method;
  
  // Entry routes
  if (path === '/api/entries' && method === 'GET') {
    return getUserEntries(request, env);
  }
  
  if (path === '/api/entries' && method === 'POST') {
    return createEntry(request, env);
  }
  
  if (path.startsWith('/api/entries/') && method === 'GET') {
    const id = path.split('/')[3];
    return getEntry(request, env, id);
  }
  
  if (path.startsWith('/api/entries/') && method === 'PUT') {
    const id = path.split('/')[3];
    return updateEntry(request, env, id);
  }
  
  if (path.startsWith('/api/entries/') && method === 'DELETE') {
    const id = path.split('/')[3];
    return deleteEntry(request, env, id);
  }
  
  // Analytics routes
  if (path.startsWith('/api/analytics/')) {
    const id = path.split('/')[3];
    return getAnalytics(request, env, id);
  }
  
  return new Response('Not Found', { status: 404 });
}

async function getUserEntries(request, env) {
  try {
    const db = new Database(env.DB);
    const url = new URL(request.url);
    const limit = Math.min(parseInt(url.searchParams.get('limit') || '50'), 100);
    const offset = parseInt(url.searchParams.get('offset') || '0');
    
    const entries = await db.getUserEntries(request.user.id, limit, offset);
    
    return new Response(JSON.stringify({ 
      success: true,
      entries 
    }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    console.error('Get entries error:', error);
    return new Response(JSON.stringify({ 
      error: error.message || 'Failed to fetch entries' 
    }), {
      status: error.status || 500,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

async function createEntry(request, env) {
  try {
    const body = await request.json();
    const { name, url, customSlug, logoUrl } = body;
    
    // Validate inputs
    if (!name || !url) {
      throw new ValidationError('Name and URL are required');
    }
    
    validateUrl(url);
    const sanitizedName = sanitizeInput(name);
    
    // Generate or validate slug
    let slug;
    if (customSlug) {
      validateCustomSlug(customSlug);
      slug = customSlug;
    } else {
      slug = generateSlug();
    }
    
    const db = new Database(env.DB);
    
    // Check if slug already exists
    const existing = await db.getEntryBySlug(slug);
    if (existing) {
      // If custom slug, throw error
      if (customSlug) {
        throw new ValidationError('This slug is already in use');
      }
      // Otherwise, generate a new one
      slug = generateSlug(8); // Try with longer slug
    }
    
    // Create entry
    const entryId = crypto.randomUUID();
    await db.createEntry({
      id: entryId,
      userId: request.user.id,
      name: sanitizedName,
      originalUrl: url,
      slug,
      logoUrl: logoUrl || null
    });
    
    // Clear cache for user entries
    if (env.CACHE) {
      await env.CACHE.delete(`user-entries:${request.user.id}`);
    }
    
    return new Response(JSON.stringify({ 
      success: true,
      entry: {
        id: entryId,
        name: sanitizedName,
        originalUrl: url,
        slug,
        shortUrl: `${env.BACKEND_URL}/${slug}`,
        logoUrl: logoUrl || null
      }
    }), {
      status: 201,
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    console.error('Create entry error:', error);
    return new Response(JSON.stringify({ 
      error: error.message || 'Failed to create entry' 
    }), {
      status: error.status || 400,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

async function getEntry(request, env, id) {
  try {
    const db = new Database(env.DB);
    const entry = await db.getEntryById(id);
    
    if (!entry) {
      throw new NotFoundError('Entry not found');
    }
    
    // Check ownership
    if (entry.user_id !== request.user.id) {
      throw new AuthError('You do not have permission to view this entry');
    }
    
    return new Response(JSON.stringify({ 
      success: true,
      entry 
    }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    console.error('Get entry error:', error);
    return new Response(JSON.stringify({ 
      error: error.message || 'Failed to fetch entry' 
    }), {
      status: error.status || 500,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

async function updateEntry(request, env, id) {
  try {
    const body = await request.json();
    const { name, url, logoUrl } = body;
    
    const db = new Database(env.DB);
    const entry = await db.getEntryById(id);
    
    if (!entry) {
      throw new NotFoundError('Entry not found');
    }
    
    // Check ownership
    if (entry.user_id !== request.user.id) {
      throw new AuthError('You do not have permission to update this entry');
    }
    
    const updates = {};
    
    if (name !== undefined) {
      updates.name = sanitizeInput(name);
    }
    
    if (url !== undefined) {
      validateUrl(url);
      updates.originalUrl = url;
    }
    
    if (logoUrl !== undefined) {
      updates.logoUrl = logoUrl;
    }
    
    if (Object.keys(updates).length > 0) {
      await db.updateEntry(id, updates);
      
      // Clear cache
      if (env.CACHE) {
        await env.CACHE.delete(`entry:${entry.slug}`);
        await env.CACHE.delete(`user-entries:${request.user.id}`);
      }
    }
    
    return new Response(JSON.stringify({ 
      success: true,
      message: 'Entry updated successfully'
    }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    console.error('Update entry error:', error);
    return new Response(JSON.stringify({ 
      error: error.message || 'Failed to update entry' 
    }), {
      status: error.status || 400,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

async function deleteEntry(request, env, id) {
  try {
    const db = new Database(env.DB);
    const entry = await db.getEntryById(id);
    
    if (!entry) {
      throw new NotFoundError('Entry not found');
    }
    
    // Check ownership
    if (entry.user_id !== request.user.id) {
      throw new AuthError('You do not have permission to delete this entry');
    }
    
    await db.deleteEntry(id);
    
    // Clear cache
    if (env.CACHE) {
      await env.CACHE.delete(`entry:${entry.slug}`);
      await env.CACHE.delete(`user-entries:${request.user.id}`);
    }
    
    // TODO: Delete associated QR code from R2
    
    return new Response(JSON.stringify({ 
      success: true,
      message: 'Entry deleted successfully'
    }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    console.error('Delete entry error:', error);
    return new Response(JSON.stringify({ 
      error: error.message || 'Failed to delete entry' 
    }), {
      status: error.status || 500,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

async function getAnalytics(request, env, id) {
  try {
    const db = new Database(env.DB);
    const entry = await db.getEntryById(id);
    
    if (!entry) {
      throw new NotFoundError('Entry not found');
    }
    
    // Check ownership
    if (entry.user_id !== request.user.id) {
      throw new AuthError('You do not have permission to view analytics for this entry');
    }
    
    const url = new URL(request.url);
    const days = parseInt(url.searchParams.get('days') || '30');
    
    const analytics = await db.getEntryAnalytics(id, days);
    
    return new Response(JSON.stringify({ 
      success: true,
      entry: {
        id: entry.id,
        name: entry.name,
        slug: entry.slug,
        clickCount: entry.click_count
      },
      analytics 
    }), {
      status: 200,
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    console.error('Get analytics error:', error);
    return new Response(JSON.stringify({ 
      error: error.message || 'Failed to fetch analytics' 
    }), {
      status: error.status || 500,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}