/**
 * API Key Management - Create, list, revoke, and manage API keys
 *
 * Provides endpoints for users to manage their API keys for webshop-data-api access.
 *
 * Related: Issue #48 - GDPR-compliant webshop sync refactoring
 */

import { createClient } from "https://esm.sh/@supabase/supabase-js@2.39.7";
import { wrapHandler } from "../_shared/error-handler.ts";
import { generateApiKey, hashApiKey } from "../_shared/api-key-auth.ts";

const FUNCTION_NAME = "api-key-management";

interface CreateKeyRequest {
  name: string;
  expires_in_days?: number;
}

interface RevokeKeyRequest {
  key_id: string;
}

interface RotateKeyRequest {
  key_id: string;
}

// ============================================================================
// Helper Functions
// ============================================================================

/**
 * Get authenticated user from request
 */
async function getAuthenticatedUser(
  req: Request,
  supabase: any
): Promise<{ user: any; error?: string }> {
  const authHeader = req.headers.get("Authorization");

  if (!authHeader) {
    return { user: null, error: "Missing authorization header" };
  }

  const { data: { user }, error } = await supabase.auth.getUser(
    authHeader.replace("Bearer ", "")
  );

  if (error || !user) {
    return { user: null, error: "Invalid or expired token" };
  }

  return { user };
}

// ============================================================================
// Route Handlers
// ============================================================================

/**
 * POST /create - Create a new API key
 */
async function handleCreateKey(
  req: Request,
  supabaseAdmin: any,
  userId: string
): Promise<Response> {
  const body: CreateKeyRequest = await req.json();

  // Validate input
  if (!body.name || body.name.trim().length < 3) {
    return new Response(
      JSON.stringify({
        success: false,
        error: "Key name must be at least 3 characters long",
        code: "INVALID_NAME",
      }),
      { status: 400, headers: { "Content-Type": "application/json" } }
    );
  }

  if (body.name.length > 100) {
    return new Response(
      JSON.stringify({
        success: false,
        error: "Key name must be at most 100 characters long",
        code: "NAME_TOO_LONG",
      }),
      { status: 400, headers: { "Content-Type": "application/json" } }
    );
  }

  // Check existing key count (limit to 10 keys per user)
  const { count, error: countError } = await supabaseAdmin
    .from("user_api_keys")
    .select("*", { count: "exact", head: true })
    .eq("user_id", userId)
    .eq("is_active", true);

  if (countError) {
    console.error("Error counting API keys:", countError);
    return new Response(
      JSON.stringify({
        success: false,
        error: "Failed to check existing keys",
        code: "DATABASE_ERROR",
      }),
      { status: 500, headers: { "Content-Type": "application/json" } }
    );
  }

  if (count && count >= 10) {
    return new Response(
      JSON.stringify({
        success: false,
        error: "Maximum API key limit reached (10 keys per user)",
        code: "KEY_LIMIT_REACHED",
      }),
      { status: 429, headers: { "Content-Type": "application/json" } }
    );
  }

  // Generate new API key
  const apiKey = generateApiKey();
  const keyHash = await hashApiKey(apiKey);

  // Calculate expiration date
  let expiresAt: string | null = null;
  if (body.expires_in_days && body.expires_in_days > 0) {
    const expiryDate = new Date();
    expiryDate.setDate(expiryDate.getDate() + body.expires_in_days);
    expiresAt = expiryDate.toISOString();
  }

  // Insert into database
  const { data: keyData, error: insertError } = await supabaseAdmin
    .from("user_api_keys")
    .insert({
      user_id: userId,
      key_name: body.name.trim(),
      api_key: apiKey,
      key_hash: keyHash,
      permissions: { webshop_data: true },
      expires_at: expiresAt,
    })
    .select()
    .single();

  if (insertError) {
    console.error("Error creating API key:", insertError);
    return new Response(
      JSON.stringify({
        success: false,
        error: "Failed to create API key",
        code: "CREATE_FAILED",
        details: insertError.message,
      }),
      { status: 500, headers: { "Content-Type": "application/json" } }
    );
  }

  // Return the plaintext API key (only time it will be shown!)
  return new Response(
    JSON.stringify({
      success: true,
      message: "API key created successfully",
      data: {
        id: keyData.id,
        name: keyData.key_name,
        api_key: apiKey, // ONLY shown here!
        expires_at: keyData.expires_at,
        created_at: keyData.created_at,
      },
      warning: "Store this API key securely. It will not be shown again!",
    }),
    { status: 201, headers: { "Content-Type": "application/json" } }
  );
}

/**
 * GET /list - List all API keys for the user
 */
async function handleListKeys(
  req: Request,
  supabaseAdmin: any,
  userId: string
): Promise<Response> {
  const { data: keys, error } = await supabaseAdmin
    .from("user_api_keys")
    .select("id, key_name, permissions, is_active, last_used_at, expires_at, created_at, updated_at")
    .eq("user_id", userId)
    .order("created_at", { ascending: false });

  if (error) {
    console.error("Error listing API keys:", error);
    return new Response(
      JSON.stringify({
        success: false,
        error: "Failed to list API keys",
        code: "LIST_FAILED",
      }),
      { status: 500, headers: { "Content-Type": "application/json" } }
    );
  }

  // Add status information to each key
  const keysWithStatus = keys.map((key: any) => {
    let status = "active";
    if (!key.is_active) {
      status = "revoked";
    } else if (key.expires_at && new Date(key.expires_at) < new Date()) {
      status = "expired";
    }

    return {
      ...key,
      status,
      // Mask the actual API key (we don't return it in list)
      api_key_preview: "api_shopcall_****",
    };
  });

  return new Response(
    JSON.stringify({
      success: true,
      data: keysWithStatus,
      count: keysWithStatus.length,
    }),
    { status: 200, headers: { "Content-Type": "application/json" } }
  );
}

/**
 * POST /revoke - Revoke an API key
 */
async function handleRevokeKey(
  req: Request,
  supabaseAdmin: any,
  userId: string
): Promise<Response> {
  const body: RevokeKeyRequest = await req.json();

  if (!body.key_id) {
    return new Response(
      JSON.stringify({
        success: false,
        error: "Missing key_id parameter",
        code: "MISSING_KEY_ID",
      }),
      { status: 400, headers: { "Content-Type": "application/json" } }
    );
  }

  // Update the key to revoked status
  const { data, error } = await supabaseAdmin
    .from("user_api_keys")
    .update({ is_active: false, updated_at: new Date().toISOString() })
    .eq("id", body.key_id)
    .eq("user_id", userId)
    .select()
    .single();

  if (error || !data) {
    console.error("Error revoking API key:", error);
    return new Response(
      JSON.stringify({
        success: false,
        error: "Failed to revoke API key. Key not found or access denied.",
        code: "REVOKE_FAILED",
      }),
      { status: 404, headers: { "Content-Type": "application/json" } }
    );
  }

  return new Response(
    JSON.stringify({
      success: true,
      message: "API key revoked successfully",
      data: {
        id: data.id,
        name: data.key_name,
        is_active: data.is_active,
      },
    }),
    { status: 200, headers: { "Content-Type": "application/json" } }
  );
}

/**
 * POST /rotate - Rotate an API key (revoke old, create new)
 */
async function handleRotateKey(
  req: Request,
  supabaseAdmin: any,
  userId: string
): Promise<Response> {
  const body: RotateKeyRequest = await req.json();

  if (!body.key_id) {
    return new Response(
      JSON.stringify({
        success: false,
        error: "Missing key_id parameter",
        code: "MISSING_KEY_ID",
      }),
      { status: 400, headers: { "Content-Type": "application/json" } }
    );
  }

  // Fetch the old key
  const { data: oldKey, error: fetchError } = await supabaseAdmin
    .from("user_api_keys")
    .select("*")
    .eq("id", body.key_id)
    .eq("user_id", userId)
    .single();

  if (fetchError || !oldKey) {
    return new Response(
      JSON.stringify({
        success: false,
        error: "API key not found or access denied",
        code: "KEY_NOT_FOUND",
      }),
      { status: 404, headers: { "Content-Type": "application/json" } }
    );
  }

  // Generate new API key
  const newApiKey = generateApiKey();
  const newKeyHash = await hashApiKey(newApiKey);

  // Start transaction (revoke old, create new)
  // First, revoke the old key
  const { error: revokeError } = await supabaseAdmin
    .from("user_api_keys")
    .update({ is_active: false, updated_at: new Date().toISOString() })
    .eq("id", body.key_id)
    .eq("user_id", userId);

  if (revokeError) {
    console.error("Error revoking old key during rotation:", revokeError);
    return new Response(
      JSON.stringify({
        success: false,
        error: "Failed to revoke old key",
        code: "ROTATION_FAILED",
      }),
      { status: 500, headers: { "Content-Type": "application/json" } }
    );
  }

  // Create new key with same name and permissions
  const { data: newKey, error: createError } = await supabaseAdmin
    .from("user_api_keys")
    .insert({
      user_id: userId,
      key_name: `${oldKey.key_name} (rotated)`,
      api_key: newApiKey,
      key_hash: newKeyHash,
      permissions: oldKey.permissions,
      expires_at: oldKey.expires_at,
    })
    .select()
    .single();

  if (createError) {
    console.error("Error creating new key during rotation:", createError);
    return new Response(
      JSON.stringify({
        success: false,
        error: "Failed to create new key",
        code: "ROTATION_FAILED",
      }),
      { status: 500, headers: { "Content-Type": "application/json" } }
    );
  }

  return new Response(
    JSON.stringify({
      success: true,
      message: "API key rotated successfully",
      data: {
        old_key_id: oldKey.id,
        new_key: {
          id: newKey.id,
          name: newKey.key_name,
          api_key: newApiKey, // ONLY shown here!
          expires_at: newKey.expires_at,
          created_at: newKey.created_at,
        },
      },
      warning: "Store this new API key securely. The old key has been revoked.",
    }),
    { status: 200, headers: { "Content-Type": "application/json" } }
  );
}

// ============================================================================
// Main Handler
// ============================================================================

Deno.serve(
  wrapHandler(FUNCTION_NAME, async (req: Request): Promise<Response> => {
    const url = new URL(req.url);

    // Handle CORS preflight
    if (req.method === "OPTIONS") {
      return new Response(null, {
        status: 204,
        headers: {
          "Access-Control-Allow-Origin": "*",
          "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
          "Access-Control-Allow-Headers": "Authorization, Content-Type",
          "Access-Control-Max-Age": "86400",
        },
      });
    }

    // Initialize Supabase clients
    const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
    const supabaseAnonKey = Deno.env.get("SUPABASE_ANON_KEY")!;
    const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;

    const supabase = createClient(supabaseUrl, supabaseAnonKey, {
      global: {
        headers: { Authorization: req.headers.get("Authorization") || "" },
      },
    });

    const supabaseAdmin = createClient(supabaseUrl, supabaseServiceKey);

    // Authenticate user
    const { user, error: authError } = await getAuthenticatedUser(
      req,
      supabase
    );

    if (authError || !user) {
      return new Response(
        JSON.stringify({
          success: false,
          error: authError || "Authentication required",
          code: "UNAUTHORIZED",
        }),
        { status: 401, headers: { "Content-Type": "application/json" } }
      );
    }

    const userId = user.id;

    // Route based on action
    const action = url.pathname.replace(/^\/api-key-management\/?/, "");

    if (req.method === "POST" && action === "create") {
      return await handleCreateKey(req, supabaseAdmin, userId);
    }

    if (req.method === "GET" && action === "list") {
      return await handleListKeys(req, supabaseAdmin, userId);
    }

    if (req.method === "POST" && action === "revoke") {
      return await handleRevokeKey(req, supabaseAdmin, userId);
    }

    if (req.method === "POST" && action === "rotate") {
      return await handleRotateKey(req, supabaseAdmin, userId);
    }

    // Unknown action
    return new Response(
      JSON.stringify({
        success: false,
        error: "Unknown action",
        code: "UNKNOWN_ACTION",
        available_actions: {
          "POST /create": "Create a new API key",
          "GET /list": "List all API keys",
          "POST /revoke": "Revoke an API key",
          "POST /rotate": "Rotate an API key (revoke old, create new)",
        },
      }),
      { status: 404, headers: { "Content-Type": "application/json" } }
    );
  })
);
