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

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

interface CoinbaseEvent {
  id: string;
  type: string;
  data: {
    id: string;
    code: string;
    name: string;
    description: string;
    pricing_type: string;
    metadata: {
      user_id: string;
      transaction_type: string;
      reference_id: string;
      billing_cycle?: string;
      is_test_mode?: string;
    };
    payments: Array<{
      network: string;
      transaction_id: string;
      status: string;
      value: {
        amount: string;
        currency: string;
      };
    }>;
    timeline: Array<{
      status: string;
      time: string;
    }>;
  };
}

// Helper to log webhook events to the database
async function logWebhookEvent(
  supabase: any,
  gateway: string,
  eventType: string,
  eventId: string | null,
  status: string,
  payload: any,
  responseStatus: number,
  errorMessage: string | null,
  startTime: number
) {
  try {
    await supabase.from("webhook_event_logs").insert({
      gateway,
      event_type: eventType,
      event_id: eventId,
      status,
      payload: typeof payload === "string" ? JSON.parse(payload) : payload,
      response_status: responseStatus,
      error_message: errorMessage,
      processing_time_ms: Date.now() - startTime,
    });
  } catch (err) {
    console.error("Failed to log webhook event:", err);
  }
}

async function verifyWebhookSignature(
  payload: string,
  signature: string,
  webhookSecret: string
): Promise<boolean> {
  try {
    const encoder = new TextEncoder();
    const key = await crypto.subtle.importKey(
      "raw",
      encoder.encode(webhookSecret),
      { name: "HMAC", hash: "SHA-256" },
      false,
      ["sign"]
    );
    
    const signatureBuffer = await crypto.subtle.sign(
      "HMAC",
      key,
      encoder.encode(payload)
    );
    
    const computedSignature = Array.from(new Uint8Array(signatureBuffer))
      .map(b => b.toString(16).padStart(2, "0"))
      .join("");
    
    return computedSignature === signature;
  } catch {
    return false;
  }
}

serve(async (req) => {
  if (req.method === "OPTIONS") {
    return new Response(null, { headers: corsHeaders });
  }

  const startTime = Date.now();
  let eventType = "unknown";
  let eventId: string | null = null;

  const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
  const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
  const supabaseAdmin = createClient(supabaseUrl, supabaseServiceKey);

  try {
    const payload = await req.text();
    const signature = req.headers.get("X-CC-Webhook-Signature");

    // Get Coinbase config for webhook secret
    const { data: gatewayConfig } = await supabaseAdmin
      .from("payment_gateway_configs")
      .select("*")
      .eq("gateway", "coinbase")
      .single();

    if (gatewayConfig) {
      const configData = gatewayConfig.is_test_mode
        ? gatewayConfig.sandbox_config
        : gatewayConfig.live_config;
      
      const webhookSecret = (configData as any)?.webhook_secret;
      
      if (webhookSecret && signature) {
        const isValid = await verifyWebhookSignature(payload, signature, webhookSecret);
        if (!isValid) {
          console.error("Invalid webhook signature");
          await logWebhookEvent(supabaseAdmin, "coinbase", eventType, eventId, "failed", { type: eventType }, 400, "Invalid webhook signature", startTime);
          return new Response(JSON.stringify({ error: "Invalid signature" }), {
            status: 400,
            headers: { ...corsHeaders, "Content-Type": "application/json" },
          });
        }
      }
    }

    const event: CoinbaseEvent = JSON.parse(payload).event;
    eventType = event.type;
    eventId = event.id;
    console.log("Coinbase webhook event:", event.type, event.data.id);

    const chargeId = event.data.id;
    const metadata = event.data.metadata;

    const { data: transaction } = await supabaseAdmin
      .from("payment_transactions")
      .select("*")
      .eq("external_transaction_id", chargeId)
      .single();

    if (!transaction) {
      console.log("Transaction not found for charge:", chargeId);
      await logWebhookEvent(supabaseAdmin, "coinbase", eventType, eventId, "processed", { type: eventType, id: eventId, note: "no transaction found" }, 200, null, startTime);
      return new Response(JSON.stringify({ received: true }), {
        status: 200,
        headers: { ...corsHeaders, "Content-Type": "application/json" },
      });
    }

    switch (event.type) {
      case "charge:confirmed":
      case "charge:resolved": {
        await supabaseAdmin
          .from("payment_transactions")
          .update({
            status: "completed",
            metadata: {
              ...transaction.metadata,
              payments: event.data.payments,
              confirmed_at: new Date().toISOString(),
            },
          })
          .eq("id", transaction.id);

        if (transaction.transaction_type === "subscription") {
          const { data: plan } = await supabaseAdmin
            .from("subscription_plans")
            .select("*")
            .eq("id", transaction.reference_id)
            .single();

          if (plan) {
            const billingCycle = metadata.billing_cycle || "monthly";
            const periodEnd = new Date();
            periodEnd.setMonth(periodEnd.getMonth() + (billingCycle === "yearly" ? 12 : 1));

            await supabaseAdmin
              .from("user_subscriptions")
              .upsert({
                user_id: transaction.user_id,
                plan_id: plan.id,
                status: "active",
                billing_cycle: billingCycle,
                payment_method: "crypto",
                current_period_start: new Date().toISOString(),
                current_period_end: periodEnd.toISOString(),
              }, { onConflict: "user_id" });

            await supabaseAdmin.rpc("add_credits", {
              p_user_id: transaction.user_id,
              p_amount: plan.monthly_credits,
              p_credit_type: "monthly",
              p_action_type: "crypto_subscription",
              p_description: `${plan.name} subscription via crypto`,
            });
          }
        } else if (transaction.transaction_type === "credit_purchase") {
          const { data: pack } = await supabaseAdmin
            .from("credit_packs")
            .select("*")
            .eq("id", transaction.reference_id)
            .single();

          if (pack) {
            await supabaseAdmin.rpc("add_credits", {
              p_user_id: transaction.user_id,
              p_amount: pack.credits,
              p_credit_type: "bonus",
              p_action_type: "crypto_purchase",
              p_description: `${pack.name} credit pack via crypto`,
            });
          }
        } else if (transaction.transaction_type === "invoice_payment") {
          await supabaseAdmin
            .from("invoices")
            .update({
              status: "paid",
              paid_at: new Date().toISOString(),
            })
            .eq("id", transaction.reference_id);
        }

        console.log("Crypto payment confirmed:", chargeId);
        break;
      }

      case "charge:failed": {
        await supabaseAdmin
          .from("payment_transactions")
          .update({
            status: "failed",
            metadata: {
              ...transaction.metadata,
              failed_at: new Date().toISOString(),
              failure_reason: "Payment failed or expired",
            },
          })
          .eq("id", transaction.id);

        console.log("Crypto payment failed:", chargeId);
        break;
      }

      case "charge:delayed": {
        await supabaseAdmin
          .from("payment_transactions")
          .update({
            metadata: {
              ...transaction.metadata,
              delayed_at: new Date().toISOString(),
              status_message: "Payment detected, awaiting confirmations",
            },
          })
          .eq("id", transaction.id);

        console.log("Crypto payment delayed (awaiting confirmations):", chargeId);
        break;
      }

      case "charge:pending": {
        console.log("Crypto payment pending:", chargeId);
        break;
      }

      default:
        console.log("Unhandled event type:", event.type);
    }

    // Log successful processing
    await logWebhookEvent(supabaseAdmin, "coinbase", eventType, eventId, "processed", { type: eventType, id: eventId }, 200, null, startTime);

    return new Response(JSON.stringify({ received: true }), {
      status: 200,
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  } catch (error) {
    console.error("Coinbase webhook error:", error);
    const message = error instanceof Error ? error.message : "Webhook processing failed";

    // Log failed processing
    await logWebhookEvent(supabaseAdmin, "coinbase", eventType, eventId, "failed", { type: eventType, id: eventId }, 500, message, startTime);

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