// app/api/appapis/register-foreign-student/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import bcrypt from 'bcryptjs';
import pool from '../../../../lib/db/db';
import { PoolConnection, RowDataPacket, ResultSetHeader } from 'mysql2/promise';

// CORS headers
const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization, x-api-key',
  'Access-Control-Allow-Credentials': 'true',
};

export async function OPTIONS() {
  return new NextResponse(null, {
    status: 204,
    headers: corsHeaders,
  });
}

// Helper function to compress/optimize base64 image
function optimizeBase64Image(base64String: string): string {
  if (!base64String) return '';
  
  // Check if it's a base64 image
  if (!base64String.startsWith('data:image')) {
    return '';
  }
  
  // Get the image type and data
  const matches = base64String.match(/^data:image\/(\w+);base64,(.+)$/);
  if (!matches) return '';
  
  const imageType = matches[1];
  const imageData = matches[2];
  
  // Calculate size in bytes
  const sizeInBytes = Buffer.byteLength(imageData, 'base64');
  const sizeInMB = sizeInBytes / (1024 * 1024);
  
  // If image is larger than 500KB, truncate it
  if (sizeInMB > 0.5) {
    console.log(`Original image size: ${sizeInMB.toFixed(2)}MB, compressing...`);
    
    // Keep only first 300KB of base64 data (approximately 400KB after encoding)
    const maxChars = 400000; // ~400KB
    const truncatedData = imageData.substring(0, maxChars);
    
    return `data:image/${imageType};base64,${truncatedData}`;
  }
  
  return base64String;
}

// Simplified password validation for mobile
const passwordSchema = z.string()
  .min(6, 'Password must be at least 6 characters')
  .max(100, 'Password cannot exceed 100 characters');

// Simplified validation schema for mobile registration
const registerSchema = z.object({
  name: z.string()
    .min(2, 'Name must be at least 2 characters')
    .max(255, 'Name cannot exceed 255 characters'),
  
  email: z.string()
    .email('Invalid email address')
    .max(255, 'Email cannot exceed 255 characters'),
  
  password: passwordSchema,
  
  phone: z.string()
    .min(5, 'Phone number must be at least 5 characters')
    .max(20, 'Phone number cannot exceed 20 characters'),
  
  country_id: z.coerce.number()
    .int('Country must be a valid ID')
    .positive('Country is required')
    .optional(),
  
  about_me: z.string()
    .max(2000, 'About me cannot exceed 2000 characters')
    .optional()
    .or(z.literal('')),
  
  profile_picture: z.string()
    .max(500000, 'Profile picture too large (max 500KB)')
    .optional()
    .or(z.literal('')),
  
  hour_rate: z.coerce.number()
    .min(0, 'Hourly rate cannot be negative')
    .max(1000, 'Hourly rate cannot exceed $1000')
    .optional()
    .default(0),
  
  gender: z.enum(['male', 'female', 'other'])
    .optional(),
  
  experience: z.string()
    .max(5000, 'Experience cannot exceed 5000 characters')
    .optional()
    .or(z.literal('')),
  
  last_education: z.enum([
    'high_school',
    'bachelors', 
    'masters',
    'phd',
    'diploma',
    'certificate'
  ]).optional(),
  
  terms_accepted: z.boolean()
    .refine((val: boolean) => val === true, {
      message: 'You must accept the terms and conditions'
    })
});

// Function to generate slug from name
function generateSlug(name: string): string {
  if (!name) return '';
  
  let slug = name.toLowerCase();
  slug = slug.replace(/[^a-z0-9\s-]/g, '');
  slug = slug.replace(/\s+/g, '-');
  slug = slug.replace(/-+/g, '-');
  slug = slug.replace(/^-+|-+$/g, '');
  
  return slug;
}

// Function to generate unique slug
async function generateUniqueSlug(
  connection: PoolConnection,
  name: string,
  maxAttempts: number = 5
): Promise<string> {
  if (!name) throw new Error('Name is required to generate slug');
  
  let baseSlug = generateSlug(name);
  if (!baseSlug) throw new Error('Could not generate slug from name');
  
  let slug = baseSlug;
  let attempts = 0;
  
  while (attempts < maxAttempts) {
    const [existingSlugs] = await connection.query<RowDataPacket[]>(
      'SELECT id FROM foreign_students WHERE user_slug = ?',
      [slug]
    );
    
    if (existingSlugs.length === 0) {
      return slug;
    }
    
    attempts++;
    if (attempts === 1) {
      const randomSuffix = Math.floor(1000 + Math.random() * 9000);
      slug = `${baseSlug}-${randomSuffix}`;
    } else {
      slug = `${baseSlug}-${1000 + attempts}`;
    }
  }
  
  const timestamp = Date.now().toString().slice(-6);
  const randomNum = Math.floor(1000 + Math.random() * 9000);
  return `${baseSlug}-${timestamp}-${randomNum}`;
}

export async function POST(request: NextRequest) {
  let connection: PoolConnection | null = null;
  
  try {
    const body = await request.json();
    console.log('Received payload keys:', Object.keys(body));
    
    // Get database connection
    connection = await pool.getConnection();
    console.log('Database connection established');
    
    await connection.beginTransaction();
    
    // Optimize profile picture if provided
    if (body.profile_picture && typeof body.profile_picture === 'string') {
      body.profile_picture = optimizeBase64Image(body.profile_picture);
      console.log('Profile picture optimized');
    }
    
    // Validate input
    const validatedData = registerSchema.parse(body);
    console.log('Validation passed');
    
    // Check if email already exists
    const [existingUsers] = await connection.query<RowDataPacket[]>(
      'SELECT id FROM foreign_students WHERE email = ?',
      [validatedData.email]
    );
    
    if (existingUsers.length > 0) {
      await connection.rollback();
      return NextResponse.json(
        { 
          success: false,
          message: 'Email already registered. Please use a different email or login.',
        },
        { status: 400, headers: corsHeaders }
      );
    }
    
    // Check if country exists (if provided)
    if (validatedData.country_id) {
      const [countryExists] = await connection.query<RowDataPacket[]>(
        'SELECT id FROM countries_db WHERE id = ?',
        [validatedData.country_id]
      );
      
      if (countryExists.length === 0) {
        await connection.rollback();
        return NextResponse.json(
          { 
            success: false,
            message: 'Selected country does not exist',
          },
          { status: 400, headers: corsHeaders }
        );
      }
    }
    
    // Generate unique slug
    const userSlug = await generateUniqueSlug(connection, validatedData.name);
    console.log('Generated slug:', userSlug);
    
    // Hash the password
    const salt = await bcrypt.genSalt(10);
    const passwordHash = await bcrypt.hash(validatedData.password, salt);
    
    // Truncate long text fields to avoid packet size issues
    const aboutMe = validatedData.about_me ? validatedData.about_me.substring(0, 1000) : null;
    const experience = validatedData.experience ? validatedData.experience.substring(0, 2000) : null;
    const profilePicture = validatedData.profile_picture ? validatedData.profile_picture.substring(0, 500000) : null; // Max 500KB
    
    // Insert new foreign student
    const [result] = await connection.query<ResultSetHeader>(
      `INSERT INTO foreign_students 
       (name, email, password_hash, phone, country_id, about_me, profile_picture, 
        hour_rate, gender, experience, last_education, user_slug, is_active, is_verified, created_at, updated_at)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 0, NOW(), NOW())`,
      [
        validatedData.name.trim(),
        validatedData.email.trim(),
        passwordHash,
        validatedData.phone.trim(),
        validatedData.country_id || null,
        aboutMe,
        profilePicture,
        validatedData.hour_rate || 0,
        validatedData.gender || null,
        experience,
        validatedData.last_education || null,
        userSlug
      ]
    );
    
    if (!result.insertId) {
      await connection.rollback();
      return NextResponse.json(
        { 
          success: false,
          message: 'Registration failed. Please try again.',
        },
        { status: 500, headers: corsHeaders }
      );
    }
    
    console.log('Student inserted with ID:', result.insertId);
    
    // Get country name for response (optional)
    let countryName: string | null = null;
    if (validatedData.country_id) {
      const [getCountry] = await connection.query<RowDataPacket[]>(
        'SELECT name FROM countries_db WHERE id = ?',
        [validatedData.country_id]
      );
      countryName = getCountry[0]?.name || null;
    }
    
    // Commit transaction
    await connection.commit();
    console.log('Transaction committed');
    
    // Prepare response data (excluding sensitive info)
    const responseData = {
      id: result.insertId,
      name: validatedData.name,
      email: validatedData.email,
      phone: validatedData.phone,
      country_id: validatedData.country_id,
      country_name: countryName,
      user_slug: userSlug,
      status: 'pending_approval'
    };
    
    // Optional: Send to CRM asynchronously with truncated data
    if (validatedData.country_id) {
      const crmPayload = {
        user_id: result.insertId,
        name: validatedData.name,
        email: validatedData.email,
        phone: validatedData.phone,
        country: countryName,
        about_me: (validatedData.about_me || '').substring(0, 1000),
        profile_picture: (validatedData.profile_picture || '').substring(0, 10000), // Only send first 10KB to CRM
        hour_rate: validatedData.hour_rate || 0,
        gender: validatedData.gender || '',
        experience: (validatedData.experience || '').substring(0, 2000),
        last_education: validatedData.last_education || '',
        registration_date: new Date().toISOString()
      };
      
      // Fire and forget - don't wait for response
      fetch("https://crm-universitiespage.com/reactapis/api/website_foreign_student/store", {
        method: "POST",
        body: JSON.stringify(crmPayload),
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `${process.env.CRM_API_KEY}`,
        },
      }).catch((crmError: Error) => {
        console.error('CRM API Error (non-blocking):', crmError);
      });
    }
    
    return NextResponse.json({
      success: true,
      message: 'Registration successful! Your account is pending approval. You will be notified once activated.',
      data: responseData
    }, { status: 201, headers: corsHeaders });
    
  } catch (error: any) {
    console.error('Registration error:', error);
    
    // Rollback transaction if connection exists
    if (connection) {
      try {
        await connection.rollback();
      } catch (rollbackError) {
        console.error('Rollback error:', rollbackError);
      }
    }
    
    // Zod validation errors
    if (error instanceof z.ZodError) {
      const errors: Record<string, string> = {};
      error.errors.forEach((err) => {
        const path = err.path.join('.');
        errors[path] = err.message;
      });
      
      return NextResponse.json(
        { 
          success: false,
          message: 'Validation failed. Please check all required fields.',
          errors 
        },
        { status: 400, headers: corsHeaders }
      );
    }
    
    // Check for packet too large error
    if (error.code === 'ER_NET_PACKET_TOO_LARGE') {
      return NextResponse.json(
        { 
          success: false,
          message: 'Profile picture is too large. Please upload a smaller image (less than 500KB).',
        },
        { status: 400, headers: corsHeaders }
      );
    }
    
    // Database or other errors
    const errorMessage = error.message || 'Registration failed. Please try again.';
    console.error('Final error message:', errorMessage);
    
    return NextResponse.json(
      { 
        success: false,
        message: errorMessage,
      },
      { status: 500, headers: corsHeaders }
    );
  } finally {
    // Always release the connection if it exists
    if (connection) {
      try {
        connection.release();
      } catch (releaseError) {
        console.error('Error releasing connection:', releaseError);
      }
    }
  }
}