// src/pages/api/contribute/tool.ts (UPDATED - Using consolidated API responses + related_software)
import type { APIRoute } from 'astro';
import { withAPIAuth } from '../../../utils/auth.js';
import { apiResponse, apiError, apiServerError, apiSpecial, handleAPIRequest } from '../../../utils/api.js';
import { GitContributionManager, type ContributionData } from '../../../utils/gitContributions.js';
import { z } from 'zod';

export const prerender = false;

const ContributionToolSchema = z.object({
  name: z.string().min(1, 'Tool name is required').max(100, 'Tool name too long'),
  icon: z.string().optional().nullable(),
  type: z.enum(['software', 'method', 'concept'], {
    errorMap: () => ({ message: 'Type must be software, method, or concept' })
  }),
  description: z.string().min(10, 'Description must be at least 10 characters').max(1000, 'Description too long'),
  domains: z.array(z.string()).default([]),
  phases: z.array(z.string()).default([]),
  platforms: z.array(z.string()).default([]),
  skillLevel: z.enum(['novice', 'beginner', 'intermediate', 'advanced', 'expert'], {
    errorMap: () => ({ message: 'Invalid skill level' })
  }),
  accessType: z.string().optional().nullable(),
  url: z.string().url('Must be a valid URL'),
  projectUrl: z.string().url('Must be a valid URL').optional().nullable(),
  license: z.string().optional().nullable(),
  knowledgebase: z.boolean().optional().nullable(),
  'domain-agnostic-software': z.array(z.string()).optional().nullable(),
  related_concepts: z.array(z.string()).optional().nullable(),
  related_software: z.array(z.string()).optional().nullable(),
  tags: z.array(z.string()).default([]),
  statusUrl: z.string().url('Must be a valid URL').optional().nullable()
});

const ContributionRequestSchema = z.object({
  action: z.enum(['add', 'edit'], {
    errorMap: () => ({ message: 'Action must be add or edit' })
  }),
  tool: ContributionToolSchema,
  metadata: z.object({
    reason: z.string().transform(val => val.trim() === '' ? undefined : val).optional(),
    contact: z.string().transform(val => val.trim() === '' ? undefined : val).optional()
  }).optional()
});

const rateLimitStore = new Map<string, { count: number; resetTime: number }>();
const RATE_LIMIT_WINDOW = 60 * 60 * 1000; // 1 hour
const RATE_LIMIT_MAX = 15; // 15 contributions per hour per user

function checkRateLimit(userId: string): boolean {
  const now = Date.now();
  const userLimit = rateLimitStore.get(userId);
  
  if (!userLimit || now > userLimit.resetTime) {
    rateLimitStore.set(userId, { count: 1, resetTime: now + RATE_LIMIT_WINDOW });
    return true;
  }
  
  if (userLimit.count >= RATE_LIMIT_MAX) {
    return false;
  }
  
  userLimit.count++;
  return true;
}

function sanitizeInput(obj: any): any {
  if (typeof obj === 'string') {
    return obj.trim().slice(0, 1000);
  }
  if (Array.isArray(obj)) {
    return obj.map(sanitizeInput);
  }
  if (obj && typeof obj === 'object') {
    const sanitized: any = {};
    for (const [key, value] of Object.entries(obj)) {
      sanitized[key] = sanitizeInput(value);
    }
    return sanitized;
  }
  return obj;
}

function preprocessFormData(body: any): any {
  // Handle comma-separated strings from autocomplete inputs
  if (body.tool) {
    // Handle tags
    if (typeof body.tool.tags === 'string') {
      body.tool.tags = body.tool.tags.split(',').map((t: string) => t.trim()).filter(Boolean);
    }
    
    // Handle related concepts
    if (body.tool.relatedConcepts) {
      if (typeof body.tool.relatedConcepts === 'string') {
        body.tool.related_concepts = body.tool.relatedConcepts.split(',').map((t: string) => t.trim()).filter(Boolean);
      } else {
        body.tool.related_concepts = body.tool.relatedConcepts;
      }
      delete body.tool.relatedConcepts; // Remove the original key
    }
    
    // Handle related software
    if (body.tool.relatedSoftware) {
      if (typeof body.tool.relatedSoftware === 'string') {
        body.tool.related_software = body.tool.relatedSoftware.split(',').map((t: string) => t.trim()).filter(Boolean);
      } else {
        body.tool.related_software = body.tool.relatedSoftware;
      }
      delete body.tool.relatedSoftware; // Remove the original key
    }
  }
  
  return body;
}

async function validateToolData(tool: any, action: string): Promise<{ valid: boolean; errors: string[] }> {
  const errors: string[] = [];
  
  try {
    const existingData = { tools: [] }; 
    
    if (action === 'add') {
      const existingNames = new Set(existingData.tools.map((t: any) => t.name.toLowerCase()));
      if (existingNames.has(tool.name.toLowerCase())) {
        errors.push('A tool with this name already exists');
      }
    }
    
    if (tool.type === 'method') {
      if (tool.platforms && tool.platforms.length > 0) {
        errors.push('Methods should not have platform information');
      }
      if (tool.license && tool.license !== null) {
        errors.push('Methods should not have license information');
      }
    } else if (tool.type === 'software') {
      if (!tool.platforms || tool.platforms.length === 0) {
        errors.push('Software tools must specify at least one platform');
      }
      if (!tool.license) {
        errors.push('Software tools must specify a license');
      }
    }
    
    // Validate related items exist (optional validation - could be enhanced)
    if (tool.related_concepts && tool.related_concepts.length > 0) {
      // Could validate that referenced concepts actually exist
      console.log('[VALIDATION] Related concepts provided:', tool.related_concepts);
    }
    
    if (tool.related_software && tool.related_software.length > 0) {
      // Could validate that referenced software actually exists
      console.log('[VALIDATION] Related software provided:', tool.related_software);
    }
    
    return { valid: errors.length === 0, errors };
    
  } catch (error) {
    console.error('Tool validation failed:', error);
    errors.push('Validation failed due to system error');
    return { valid: false, errors };
  }
}

export const POST: APIRoute = async ({ request }) => {
  return await handleAPIRequest(async () => {
    const authResult = await withAPIAuth(request, 'contributions');
    if (authResult.authRequired && !authResult.authenticated) {
      return apiError.unauthorized();
    }

    const userId = authResult.session?.userId || 'anonymous';
    const userEmail = authResult.session?.email || 'anon@anon.anon';

    if (!checkRateLimit(userId)) {
      return apiError.rateLimit('Rate limit exceeded. Please wait before submitting another contribution.');
    }

    let body;
    try {
      const rawBody = await request.text();
      if (!rawBody.trim()) {
        return apiSpecial.emptyBody();
      }
      body = JSON.parse(rawBody);
    } catch (error) {
      return apiSpecial.invalidJSON();
    }

    // Preprocess form data to handle autocomplete inputs
    body = preprocessFormData(body);
    
    const sanitizedBody = sanitizeInput(body);

    let validatedData;
    try {
      validatedData = ContributionRequestSchema.parse(sanitizedBody);
    } catch (error) {
      if (error instanceof z.ZodError) {
        const errorMessages = error.errors.map(err => 
          `${err.path.join('.')}: ${err.message}`
        );
        console.log('[VALIDATION] Zod validation errors:', errorMessages);
        return apiError.validation('Validation failed', errorMessages);
      }
      
      return apiError.badRequest('Invalid request data');
    }

    const toolValidation = await validateToolData(validatedData.tool, validatedData.action);
    if (!toolValidation.valid) {
      return apiError.validation('Tool validation failed', toolValidation.errors);
    }

    const contributionData: ContributionData = {
      type: validatedData.action,
      tool: validatedData.tool,
      metadata: {
        submitter: userEmail,
        reason: validatedData.metadata?.reason,
        contact: validatedData.metadata?.contact
      }
    };

    console.log('[CONTRIBUTION] Processing contribution:', {
      type: contributionData.type,
      toolName: contributionData.tool.name,
      toolType: contributionData.tool.type,
      submitter: userEmail,
      hasRelatedConcepts: !!(contributionData.tool.related_concepts?.length),
      hasRelatedSoftware: !!(contributionData.tool.related_software?.length),
      tagsCount: contributionData.tool.tags?.length || 0
    });

    try {
      const gitManager = new GitContributionManager();
      const result = await gitManager.submitContribution(contributionData);

      if (result.success) {
        console.log(`[CONTRIBUTION] Issue created for "${validatedData.tool.name}" by ${userEmail} - Issue: ${result.issueUrl}`);
        
        return apiResponse.created({
          success: true,
          message: result.message,
          issueUrl: result.issueUrl,
          issueNumber: result.issueNumber
        });
      } else {
        console.error(`[CONTRIBUTION FAILED] "${validatedData.tool.name}" by ${userEmail}: ${result.message}`);
        
        return apiServerError.internal(`Contribution failed: ${result.message}`);
      }
    } catch (gitError) {
      console.error(`[GIT ERROR] ${validatedData.action} "${validatedData.tool.name}" by ${userEmail}:`, gitError);
      
      const errorMessage = gitError instanceof Error ? gitError.message : 'Git operation failed';
      return apiServerError.internal(`Git operation failed: ${errorMessage}`);
    }

  }, 'Contribution processing failed');
};