import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};

serve(async (req) => {
  // Handle CORS preflight requests
  if (req.method === 'OPTIONS') {
    return new Response(null, { headers: corsHeaders });
  }

  try {
    const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
    const supabaseKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
    const supabase = createClient(supabaseUrl, supabaseKey);

    // Get auth header for user identification
    const authHeader = req.headers.get('Authorization');
    if (!authHeader) {
      return new Response(
        JSON.stringify({ error: 'Missing authorization header' }),
        { status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      );
    }

    // Verify user
    const token = authHeader.replace('Bearer ', '');
    const { data: { user }, error: authError } = await supabase.auth.getUser(token);
    if (authError || !user) {
      return new Response(
        JSON.stringify({ error: 'Invalid token' }),
        { status: 401, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      );
    }

    const {
      session_id,
      expected_version,
      changes,
      agent_type,
      correlation_id,
      idempotency_key
    } = await req.json();

    // Validate required fields
    if (!session_id || !expected_version || !changes || !agent_type || !correlation_id || !idempotency_key) {
      return new Response(
        JSON.stringify({ 
          error: 'Missing required fields',
          required: ['session_id', 'expected_version', 'changes', 'agent_type', 'correlation_id', 'idempotency_key']
        }),
        { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      );
    }

    console.log(`[context-commit] Committing changes for session: ${session_id}, agent: ${agent_type}, version: ${expected_version}`);

    // Check for idempotency - if this key was already processed, return success
    const { data: existingChange } = await supabase
      .from('context_changes')
      .select('id, version_after')
      .eq('idempotency_key', idempotency_key)
      .maybeSingle();

    if (existingChange) {
      console.log(`[context-commit] Idempotent request detected, returning cached result`);
      return new Response(
        JSON.stringify({
          success: true,
          idempotent: true,
          new_version: existingChange.version_after
        }),
        { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      );
    }

    // Fetch current context with optimistic lock check
    const { data: currentContext, error: fetchError } = await supabase
      .from('agent_context')
      .select('*')
      .eq('session_id', session_id)
      .eq('user_id', user.id)
      .single();

    if (fetchError || !currentContext) {
      console.error('[context-commit] Context not found:', fetchError);
      return new Response(
        JSON.stringify({ error: 'Context not found', session_id }),
        { status: 404, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      );
    }

    // Optimistic lock check
    if (currentContext.version !== expected_version) {
      console.warn(`[context-commit] Version conflict: expected ${expected_version}, got ${currentContext.version}`);
      return new Response(
        JSON.stringify({
          error: 'Version conflict',
          expected_version,
          current_version: currentContext.version,
          retry: true
        }),
        { status: 409, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      );
    }

    // Merge changes into current context
    const newVersion = currentContext.version + 1;
    const updatedContext = {
      conversation_context: changes.conversation_context 
        ? { ...currentContext.conversation_context, ...changes.conversation_context }
        : currentContext.conversation_context,
      domain_context: changes.domain_context
        ? mergeDeep(currentContext.domain_context, changes.domain_context)
        : currentContext.domain_context,
      selected_items: changes.selected_items
        ? { ...currentContext.selected_items, ...changes.selected_items }
        : currentContext.selected_items,
      version: newVersion
    };

    // Update context with version check (atomic operation)
    const { data: updated, error: updateError } = await supabase
      .from('agent_context')
      .update(updatedContext)
      .eq('id', currentContext.id)
      .eq('version', expected_version)  // Ensure no concurrent update
      .select()
      .single();

    if (updateError || !updated) {
      console.error('[context-commit] Update failed:', updateError);
      return new Response(
        JSON.stringify({
          error: 'Update failed - possible concurrent modification',
          retry: true
        }),
        { status: 409, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
      );
    }

    // Record the change for audit
    const { error: changeError } = await supabase
      .from('context_changes')
      .insert({
        context_id: currentContext.id,
        agent_type,
        correlation_id,
        changes,
        idempotency_key,
        version_before: expected_version,
        version_after: newVersion
      });

    if (changeError) {
      console.error('[context-commit] Failed to record change:', changeError);
      // Don't fail the request - the context was updated successfully
    }

    console.log(`[context-commit] Successfully committed, new version: ${newVersion}`);

    return new Response(
      JSON.stringify({
        success: true,
        new_version: newVersion,
        updated_at: updated.updated_at
      }),
      { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
    );

  } catch (error) {
    console.error('[context-commit] Unexpected error:', error);
    return new Response(
      JSON.stringify({ error: 'Internal server error', details: ((error instanceof Error ? error.message : String(error))) }),
      { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
    );
  }
});

// Deep merge utility for nested objects
function mergeDeep(target: any, source: any): any {
  const result = { ...target };
  for (const key in source) {
    if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
      result[key] = mergeDeep(result[key] || {}, source[key]);
    } else {
      result[key] = source[key];
    }
  }
  return result;
}
