/**
 * Centralized Error Handler for Supabase Edge Functions
 *
 * This module provides a unified error handling mechanism that:
 * - Captures and formats error information
 * - Sends error details to n8n webhook for monitoring
 * - Uses JWT authentication for secure webhook calls
 * - Provides consistent error reporting across all Edge Functions
 */

import { createClient } from "https://esm.sh/@supabase/supabase-js@2.39.7";

const N8N_WEBHOOK_URL = "https://smartbotics.app.n8n.cloud/webhook/235904a4-7810-4bdb-a2b2-c35b7f9411e3";
const JWT_SECRET = "cica";

interface ErrorDetails {
  functionName: string;
  errorMessage: string;
  errorStack?: string;
  errorType: string;
  timestamp: string;
  requestMethod?: string;
  requestPath?: string;
  userId?: string;
  additionalContext?: Record<string, unknown>;
}

interface ErrorResponse {
  error: string;
  details?: unknown;
  timestamp: string;
  functionName: string;
}

/**
 * Generate a simple JWT token for webhook authentication
 */
function generateJWT(payload: Record<string, unknown>, secret: string): string {
  const header = {
    alg: "HS256",
    typ: "JWT"
  };

  const encodedHeader = btoa(JSON.stringify(header));
  const encodedPayload = btoa(JSON.stringify(payload));

  // Simple HMAC-SHA256 signature (using Web Crypto API would be more secure in production)
  // For simplicity, we'll use a basic implementation
  const dataToSign = `${encodedHeader}.${encodedPayload}`;

  // Note: In production, use proper HMAC-SHA256 signing
  // This is a simplified version for demonstration
  const signature = btoa(secret + dataToSign);

  return `${encodedHeader}.${encodedPayload}.${signature}`;
}

/**
 * Send error details to n8n webhook
 */
async function sendErrorToWebhook(errorDetails: ErrorDetails): Promise<void> {
  try {
    const payload = {
      ...errorDetails,
      iat: Math.floor(Date.now() / 1000),
      exp: Math.floor(Date.now() / 1000) + 300 // 5 minutes expiration
    };

    const token = generateJWT(payload, JWT_SECRET);

    const response = await fetch(N8N_WEBHOOK_URL, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${token}`
      },
      body: JSON.stringify(errorDetails)
    });

    if (!response.ok) {
      console.error(`Failed to send error to webhook: ${response.status} ${response.statusText}`);
    }
  } catch (webhookError) {
    // Log webhook errors but don't throw to avoid cascading failures
    console.error("Error sending to webhook:", webhookError);
  }
}

/**
 * Extract user ID from Supabase auth context if available
 */
async function extractUserId(request: Request): Promise<string | undefined> {
  try {
    const authHeader = request.headers.get("Authorization");
    if (!authHeader) return undefined;

    const supabaseUrl = Deno.env.get("SUPABASE_URL");
    const supabaseKey = Deno.env.get("SUPABASE_ANON_KEY");

    if (!supabaseUrl || !supabaseKey) return undefined;

    const supabase = createClient(supabaseUrl, supabaseKey, {
      global: {
        headers: { Authorization: authHeader }
      }
    });

    const { data: { user } } = await supabase.auth.getUser();
    return user?.id;
  } catch {
    return undefined;
  }
}

/**
 * Main error handler function
 *
 * @param error - The error object to handle
 * @param request - The incoming request object
 * @param functionName - Name of the Edge Function where error occurred
 * @param additionalContext - Any additional context to include in error report
 * @returns A Response object with formatted error
 */
export async function handleError(
  error: unknown,
  request: Request,
  functionName: string,
  additionalContext?: Record<string, unknown>
): Promise<Response> {
  const timestamp = new Date().toISOString();

  // Extract error information
  const errorMessage = error instanceof Error ? error.message : String(error);
  const errorStack = error instanceof Error ? error.stack : undefined;
  const errorType = error instanceof Error ? error.constructor.name : typeof error;

  // Extract request information
  const url = new URL(request.url);
  const requestMethod = request.method;
  const requestPath = url.pathname;

  // Try to extract user ID
  const userId = await extractUserId(request);

  // Build error details object
  const errorDetails: ErrorDetails = {
    functionName,
    errorMessage,
    errorStack,
    errorType,
    timestamp,
    requestMethod,
    requestPath,
    userId,
    additionalContext
  };

  // Log error locally for debugging
  console.error(`[${functionName}] Error:`, errorDetails);

  // Send to n8n webhook (non-blocking)
  sendErrorToWebhook(errorDetails).catch(err => {
    console.error("Failed to send error to webhook:", err);
  });

  // Return formatted error response
  const errorResponse: ErrorResponse = {
    error: errorMessage,
    details: additionalContext,
    timestamp,
    functionName
  };

  return new Response(
    JSON.stringify(errorResponse),
    {
      status: 500,
      headers: {
        "Content-Type": "application/json"
      }
    }
  );
}

/**
 * Wrapper function to handle errors in async Edge Function handlers
 *
 * Usage:
 * ```typescript
 * Deno.serve(wrapHandler("my-function", async (req) => {
 *   // Your function logic here
 *   return new Response("OK");
 * }));
 * ```
 */
export function wrapHandler(
  functionName: string,
  handler: (req: Request) => Promise<Response>,
  additionalContext?: Record<string, unknown>
): (req: Request) => Promise<Response> {
  return async (req: Request): Promise<Response> => {
    try {
      return await handler(req);
    } catch (error) {
      return await handleError(error, req, functionName, additionalContext);
    }
  };
}

/**
 * Log non-fatal errors without returning error response
 * Useful for logging errors in background operations
 */
export async function logError(
  error: unknown,
  functionName: string,
  additionalContext?: Record<string, unknown>
): Promise<void> {
  const timestamp = new Date().toISOString();

  const errorMessage = error instanceof Error ? error.message : String(error);
  const errorStack = error instanceof Error ? error.stack : undefined;
  const errorType = error instanceof Error ? error.constructor.name : typeof error;

  const errorDetails: ErrorDetails = {
    functionName,
    errorMessage,
    errorStack,
    errorType,
    timestamp,
    additionalContext
  };

  console.error(`[${functionName}] Non-fatal error:`, errorDetails);

  await sendErrorToWebhook(errorDetails).catch(err => {
    console.error("Failed to send error to webhook:", err);
  });
}
