import type { APIRoute } from 'astro';
import { withAPIAuth } from '../../../utils/auth.js';
import { apiResponse, apiError, apiServerError, apiSpecial, handleAPIRequest } from '../../../utils/api.js';
import { NextcloudUploader, isNextcloudConfigured } from '../../../utils/nextcloud.js';
import { promises as fs } from 'fs';
import path from 'path';
import crypto from 'crypto';

export const prerender = false;

interface UploadResult {
  success: boolean;
  url?: string;
  filename?: string;
  size?: number;
  error?: string;
  storage?: 'nextcloud' | 'local';
}

const UPLOAD_CONFIG = {
  maxFileSize: 50 * 1024 * 1024, // 50MB
  allowedTypes: new Set([
    'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml',
    
    'video/mp4', 'video/webm', 'video/ogg', 'video/avi', 'video/mov',
    
    'application/pdf',
    'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'application/vnd.ms-excel',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'application/vnd.ms-powerpoint',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation',
    
    'text/plain', 
    'text/csv', 
    'text/markdown',          
    'text/x-markdown',         
    'application/json',
    'application/xml',
    'text/xml',
    'text/html',
    
    'application/zip', 
    'application/x-tar', 
    'application/gzip',
    'application/x-gzip',
    'application/x-zip-compressed',
    'application/x-rar-compressed',
    'application/x-7z-compressed',
    
    'application/rtf',
    'text/richtext',
    'application/x-yaml',
    'text/yaml',
    'application/yaml'
  ]),
  localUploadPath: process.env.LOCAL_UPLOAD_PATH || './public/uploads',
  publicBaseUrl: process.env.PUBLIC_BASE_URL || 'http://localhost:4321'
};

const uploadRateLimit = new Map<string, { count: number; resetTime: number }>();
const RATE_LIMIT_WINDOW = 60 * 60 * 1000; // 1 hour
const RATE_LIMIT_MAX = 10; // Max 10 uploads per hour per user

function checkUploadRateLimit(userEmail: string): boolean {
  const now = Date.now();
  const userLimit = uploadRateLimit.get(userEmail);
  
  if (!userLimit || now > userLimit.resetTime) {
    uploadRateLimit.set(userEmail, { count: 1, resetTime: now + RATE_LIMIT_WINDOW });
    return true;
  }
  
  if (userLimit.count >= RATE_LIMIT_MAX) {
    console.warn(`[UPLOAD] Rate limit exceeded for user: ${userEmail} (${userLimit.count}/${RATE_LIMIT_MAX})`);
    return false;
  }
  
  userLimit.count++;
  return true;
}

function validateFile(file: File): { valid: boolean; error?: string } {
  console.log(`[UPLOAD] Validating file: ${file.name}, size: ${file.size}, type: ${file.type}`);
  
  if (file.size > UPLOAD_CONFIG.maxFileSize) {
    const errorMsg = `File too large. Maximum size is ${Math.round(UPLOAD_CONFIG.maxFileSize / 1024 / 1024)}MB`;
    console.warn(`[UPLOAD] ${errorMsg} - File size: ${file.size}`);
    return { valid: false, error: errorMsg };
  }
  
  if (!UPLOAD_CONFIG.allowedTypes.has(file.type)) {
    const errorMsg = `File type ${file.type} not allowed`;
    console.warn(`[UPLOAD] ${errorMsg} - Allowed types:`, Array.from(UPLOAD_CONFIG.allowedTypes));
    return { valid: false, error: errorMsg };
  }
  
  console.log(`[UPLOAD] File validation passed for: ${file.name}`);
  return { valid: true };
}

async function uploadToNextcloud(file: File, userEmail: string): Promise<UploadResult> {
  console.log(`[UPLOAD] Attempting Nextcloud upload for: ${file.name} by ${userEmail}`);
  
  try {
    const uploader = new NextcloudUploader();
    const result = await uploader.uploadFile(file, userEmail);
    
    console.log(`[UPLOAD] Nextcloud upload successful:`, {
      filename: result.filename,
      url: result.url,
      size: file.size
    });
    
    return {
      success: true,
      url: result.url,
      filename: result.filename,
      size: file.size,
      storage: 'nextcloud'
    };
  } catch (error) {
    console.error('[UPLOAD] Nextcloud upload failed:', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Nextcloud upload failed',
      storage: 'nextcloud'
    };
  }
}

async function uploadToLocal(file: File, userType: string): Promise<UploadResult> {
  console.log(`[UPLOAD] Attempting local upload for: ${file.name} (${userType})`);
  
  try {
    console.log(`[UPLOAD] Creating directory: ${UPLOAD_CONFIG.localUploadPath}`);
    await fs.mkdir(UPLOAD_CONFIG.localUploadPath, { recursive: true });
    
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const randomString = crypto.randomBytes(8).toString('hex');
    const extension = path.extname(file.name);
    const filename = `${timestamp}-${randomString}${extension}`;
    
    const filepath = path.join(UPLOAD_CONFIG.localUploadPath, filename);
    console.log(`[UPLOAD] Writing file to: ${filepath}`);
    
    const buffer = Buffer.from(await file.arrayBuffer());
    await fs.writeFile(filepath, buffer);
    
    const publicUrl = `${UPLOAD_CONFIG.publicBaseUrl}/uploads/${filename}`;
    
    console.log(`[UPLOAD] Local upload successful:`, {
      filename,
      filepath,
      publicUrl,
      size: file.size
    });
    
    return {
      success: true,
      url: publicUrl,
      filename: filename,
      size: file.size,
      storage: 'local'
    };
  } catch (error) {
    console.error('[UPLOAD] Local upload failed:', error);
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Local upload failed',
      storage: 'local'
    };
  }
}

export const POST: APIRoute = async ({ request }) => {
  return await handleAPIRequest(async () => {
    console.log('[UPLOAD] Processing upload request');
    
    const authResult = await withAPIAuth(request, 'contributions');
    console.log('[UPLOAD] Auth result:', {
      authenticated: authResult.authenticated,
      authRequired: authResult.authRequired,
      userId: authResult.userId
    });
    
    if (authResult.authRequired && !authResult.authenticated) {
      console.warn('[UPLOAD] Upload rejected - authentication required but user not authenticated');
      return apiError.unauthorized('Authentication required for file uploads');
    }

    const userEmail = authResult.session?.email || 'anon@anon.anon';
    console.log(`[UPLOAD] Processing upload for user: ${userEmail}`);

    if (!checkUploadRateLimit(userEmail)) {
      return apiError.rateLimit('Upload rate limit exceeded. Please wait before uploading again.');
    }

    let formData;
    try {
      console.log('[UPLOAD] Parsing form data');
      formData = await request.formData();
      console.log('[UPLOAD] Form data keys:', Array.from(formData.keys()));
    } catch (error) {
      console.error('[UPLOAD] Failed to parse form data:', error);
      return apiError.badRequest('Invalid form data - could not parse request');
    }

    const file = formData.get('file') as File;
    const type = formData.get('type') as string;

    if (!file) {
      console.warn('[UPLOAD] No file provided in request');
      return apiSpecial.missingRequired(['file']);
    }

    console.log(`[UPLOAD] Processing file: ${file.name}, type parameter: ${type}`);

    const validation = validateFile(file);
    if (!validation.valid) {
      return apiError.badRequest(validation.error!);
    }

    const nextcloudConfigured = isNextcloudConfigured();
    console.log('[UPLOAD] Environment check:', {
      nextcloudConfigured,
      localUploadPath: UPLOAD_CONFIG.localUploadPath,
      publicBaseUrl: UPLOAD_CONFIG.publicBaseUrl,
      nodeEnv: process.env.NODE_ENV
    });

    let result: UploadResult;
    
    if (nextcloudConfigured) {
      console.log('[UPLOAD] Using Nextcloud as primary storage');
      result = await uploadToNextcloud(file, userEmail);
      
      if (!result.success) {
        console.warn('[UPLOAD] Nextcloud upload failed, trying local fallback:', result.error);
        result = await uploadToLocal(file, type);
      }
    } else {
      console.log('[UPLOAD] Using local storage (Nextcloud not configured)');
      result = await uploadToLocal(file, type);
    }
    
    if (result.success) {
      console.log(`[UPLOAD] Upload completed successfully:`, {
        filename: result.filename,
        storage: result.storage,
        url: result.url,
        user: userEmail
      });
      
      return apiSpecial.uploadSuccess({
        url: result.url!,
        filename: result.filename!,
        size: result.size!,
        storage: result.storage!
      });
    } else {
      console.error(`[UPLOAD] Upload failed completely:`, {
        filename: file.name,
        error: result.error,
        storage: result.storage,
        user: userEmail
      });
      
      return apiSpecial.uploadFailed(result.error!);
    }
    
  }, 'Media upload processing failed');
};

export const GET: APIRoute = async ({ request }) => {
  return await handleAPIRequest(async () => {
    console.log('[UPLOAD] Getting upload status');
    
    const authResult = await withAPIAuth(request);
    if (authResult.authRequired && !authResult.authenticated) {
      return apiError.unauthorized();
    }

    const nextcloudConfigured = isNextcloudConfigured();

    let localStorageAvailable = false;
    try {
      await fs.access(UPLOAD_CONFIG.localUploadPath);
      localStorageAvailable = true;
      console.log('[UPLOAD] Local storage accessible');
    } catch {
      try {
        await fs.mkdir(UPLOAD_CONFIG.localUploadPath, { recursive: true });
        localStorageAvailable = true;
        console.log('[UPLOAD] Local storage created');
      } catch (error) {
        console.warn('[UPLOAD] Local upload directory not accessible:', error);
      }
    }
    
    const status = {
      storage: {
        nextcloud: {
          configured: nextcloudConfigured,
          primary: nextcloudConfigured
        },
        local: {
          available: localStorageAvailable,
          fallback: nextcloudConfigured,
          primary: !nextcloudConfigured
        }
      },
      limits: {
        maxFileSize: UPLOAD_CONFIG.maxFileSize,
        maxFileSizeMB: Math.round(UPLOAD_CONFIG.maxFileSize / 1024 / 1024),
        allowedTypes: Array.from(UPLOAD_CONFIG.allowedTypes),
        rateLimit: {
          maxPerHour: RATE_LIMIT_MAX,
          windowMs: RATE_LIMIT_WINDOW
        }
      },
      paths: {
        uploadEndpoint: '/api/upload/media',
        localPath: localStorageAvailable ? '/uploads' : null
      },
      environment: {
        nodeEnv: process.env.NODE_ENV,
        publicBaseUrl: UPLOAD_CONFIG.publicBaseUrl
      }
    };
    
    console.log('[UPLOAD] Status check completed:', status);
    return apiResponse.success(status);
    
  }, 'Upload status retrieval failed');
};