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

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

const logStep = (step: string, details?: Record<string, unknown>) => {
  const detailsStr = details ? ` - ${JSON.stringify(details)}` : '';
  console.log(`[STRIPE-WEBHOOK] ${step}${detailsStr}`);
};

// 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);
  }
}

// Helper function to send email notifications
async function sendEmailNotification(
  supabaseUrl: string,
  supabaseServiceKey: string,
  to: string,
  templateName: string,
  variables: Record<string, string>
) {
  try {
    const response = await fetch(`${supabaseUrl}/functions/v1/send-email`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${supabaseServiceKey}`,
      },
      body: JSON.stringify({ to, templateName, variables }),
    });
    
    if (!response.ok) {
      const error = await response.text();
      logStep("Email notification failed", { templateName, error });
    } else {
      logStep("Email notification sent", { templateName, to });
    }
  } catch (error) {
    logStep("Email notification error", { templateName, error: String(error) });
  }
}

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 supabase = createClient(supabaseUrl, supabaseServiceKey);

  try {
    const stripeKey = Deno.env.get("STRIPE_SECRET_KEY");
    const webhookSecret = Deno.env.get("STRIPE_WEBHOOK_SECRET");
    
    if (!stripeKey) {
      throw new Error("Stripe secret key not configured");
    }

    if (!webhookSecret) {
      logStep("WARNING: STRIPE_WEBHOOK_SECRET not configured - signature verification disabled");
    }

    const stripe = new Stripe(stripeKey, {
      apiVersion: "2025-08-27.basil",
    });

    const body = await req.text();
    let event: Stripe.Event;

    // Verify webhook signature if secret is configured
    if (webhookSecret) {
      const signature = req.headers.get("stripe-signature");
      if (!signature) {
        throw new Error("No stripe signature header");
      }
      try {
        event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
        logStep("Webhook signature verified successfully");
      } catch (err) {
        const message = err instanceof Error ? err.message : "Unknown error";
        logStep("Webhook signature verification failed", { error: message });
        throw new Error(`Webhook signature verification failed: ${message}`);
      }
    } else {
      event = JSON.parse(body);
    }

    eventType = event.type;
    eventId = event.id;
    logStep("Processing webhook event", { type: event.type, id: event.id });

    // Get origin for email links
    const origin = Deno.env.get("PUBLIC_SITE_URL") || "https://appforge.dev";

    switch (event.type) {
      // ==================== CHECKOUT COMPLETED ====================
      case "checkout.session.completed": {
        const session = event.data.object as Stripe.Checkout.Session;
        const metadata = session.metadata || {};
        logStep("Checkout session completed", { sessionId: session.id, metadata });

        if (metadata.type === "subscription") {
          const userId = metadata.user_id;
          const planId = metadata.plan_id;
          const billingCycle = metadata.billing_cycle;

          // Get user profile for email
          const { data: profile } = await supabase
            .from("profiles")
            .select("email, display_name")
            .eq("id", userId)
            .single();

          // Get plan details for credits
          const { data: plan, error: planError } = await supabase
            .from("subscription_plans")
            .select("monthly_credits, name")
            .eq("id", planId)
            .single();

          if (planError) {
            logStep("Error fetching plan", { error: planError.message });
          }

          // Update or create user subscription
          const periodEnd = new Date(Date.now() + (billingCycle === "yearly" ? 365 : 30) * 24 * 60 * 60 * 1000);
          const { error: subError } = await supabase
            .from("user_subscriptions")
            .upsert({
              user_id: userId,
              plan_id: planId,
              billing_cycle: billingCycle,
              status: "active",
              external_subscription_id: session.subscription as string,
              current_period_start: new Date().toISOString(),
              current_period_end: periodEnd.toISOString(),
              payment_method: "stripe",
            }, { onConflict: "user_id" });

          if (subError) {
            logStep("Error updating subscription", { error: subError.message });
          }

          // Update user credits
          if (plan) {
            const { error: creditsError } = await supabase
              .from("user_credits")
              .update({
                monthly_credits: plan.monthly_credits,
                credits_reset_at: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(),
              })
              .eq("user_id", userId);

            if (creditsError) {
              logStep("Error updating credits", { error: creditsError.message });
            }
          }

          // Record transaction
          const { error: txError } = await supabase.from("payment_transactions").insert({
            user_id: userId,
            amount: (session.amount_total || 0) / 100,
            currency: session.currency?.toUpperCase() || "USD",
            payment_method: "stripe",
            status: "completed",
            transaction_type: "subscription",
            reference_id: planId,
            external_transaction_id: session.payment_intent as string,
          });

          if (txError) {
            logStep("Error recording transaction", { error: txError.message });
          }

          logStep("Subscription activated", { userId, planName: plan?.name });

          // Send subscription activation email
          if (profile?.email && plan) {
            await sendEmailNotification(supabaseUrl, supabaseServiceKey, profile.email, "subscription_activated", {
              user_name: profile.display_name || profile.email.split("@")[0],
              plan_name: plan.name,
              credits: String(plan.monthly_credits),
              billing_cycle: billingCycle === "yearly" ? "Yearly" : "Monthly",
              next_billing_date: periodEnd.toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }),
              dashboard_url: `${origin}/dashboard`,
            });
          }

        } else if (metadata.type === "credits") {
          const userId = metadata.user_id;
          const credits = parseInt(metadata.credits, 10);

          // Get user profile for email
          const { data: profile } = await supabase
            .from("profiles")
            .select("email, display_name")
            .eq("id", userId)
            .single();

          // Add bonus credits
          const { error: addError } = await supabase.rpc("add_credits", {
            p_user_id: userId,
            p_amount: credits,
            p_credit_type: "bonus",
            p_action_type: "purchase",
            p_description: `Purchased ${credits} credit pack`,
          });

          if (addError) {
            logStep("Error adding credits", { error: addError.message });
          }

          // Record transaction
          const amount = (session.amount_total || 0) / 100;
          const currency = session.currency?.toUpperCase() || "USD";
          const { error: txError } = await supabase.from("payment_transactions").insert({
            user_id: userId,
            amount,
            currency,
            payment_method: "stripe",
            status: "completed",
            transaction_type: "credits",
            reference_id: metadata.credit_pack_id,
            external_transaction_id: session.payment_intent as string,
          });

          if (txError) {
            logStep("Error recording transaction", { error: txError.message });
          }

          logStep("Credits added", { userId, credits });

          // Send credits purchase email
          if (profile?.email) {
            await sendEmailNotification(supabaseUrl, supabaseServiceKey, profile.email, "credits_purchased", {
              user_name: profile.display_name || profile.email.split("@")[0],
              credits: String(credits),
              amount: `$${amount.toFixed(2)} ${currency}`,
              dashboard_url: `${origin}/dashboard`,
            });
          }
        }
        break;
      }

      // ==================== SUBSCRIPTION CREATED ====================
      case "customer.subscription.created": {
        const subscription = event.data.object as Stripe.Subscription;
        const customerId = subscription.customer as string;
        logStep("Subscription created", { subscriptionId: subscription.id, customerId });

        const { data: profile } = await supabase
          .from("profiles")
          .select("id")
          .eq("stripe_customer_id", customerId)
          .single();

        if (profile) {
          logStep("Found user for new subscription", { userId: profile.id });
        } else {
          logStep("No user found for customer", { customerId });
        }
        break;
      }

      // ==================== SUBSCRIPTION UPDATED ====================
      case "customer.subscription.updated": {
        const subscription = event.data.object as Stripe.Subscription;
        const customerId = subscription.customer as string;
        logStep("Subscription updated", { 
          subscriptionId: subscription.id, 
          status: subscription.status,
          cancelAtPeriodEnd: subscription.cancel_at_period_end 
        });

        const { data: profile } = await supabase
          .from("profiles")
          .select("id, email, display_name")
          .eq("stripe_customer_id", customerId)
          .single();

        if (profile) {
          const { error } = await supabase
            .from("user_subscriptions")
            .update({
              status: subscription.status,
              cancel_at_period_end: subscription.cancel_at_period_end,
              current_period_start: new Date(subscription.current_period_start * 1000).toISOString(),
              current_period_end: new Date(subscription.current_period_end * 1000).toISOString(),
            })
            .eq("user_id", profile.id);

          if (error) {
            logStep("Error updating subscription", { error: error.message });
          } else {
            logStep("Subscription status updated", { userId: profile.id, status: subscription.status });
          }
        } else {
          logStep("No user found for customer", { customerId });
        }
        break;
      }

      // ==================== SUBSCRIPTION DELETED ====================
      case "customer.subscription.deleted": {
        const subscription = event.data.object as Stripe.Subscription;
        const customerId = subscription.customer as string;
        logStep("Subscription deleted/canceled", { subscriptionId: subscription.id, customerId });

        const { data: profile } = await supabase
          .from("profiles")
          .select("id, email, display_name")
          .eq("stripe_customer_id", customerId)
          .single();

        if (profile) {
          // Get current plan name before downgrading
          const { data: currentSub } = await supabase
            .from("user_subscriptions")
            .select("plan_id, subscription_plans(name)")
            .eq("user_id", profile.id)
            .single();

          const previousPlanName = (currentSub?.subscription_plans as any)?.name || "Premium";

          // Get free plan
          const { data: freePlan } = await supabase
            .from("subscription_plans")
            .select("id, monthly_credits")
            .eq("tier", "free")
            .single();

          if (freePlan) {
            // Downgrade to free plan
            await supabase
              .from("user_subscriptions")
              .update({
                plan_id: freePlan.id,
                status: "active",
                external_subscription_id: null,
                payment_method: null,
                cancel_at_period_end: false,
              })
              .eq("user_id", profile.id);

            // Reset credits to free tier
            await supabase
              .from("user_credits")
              .update({ monthly_credits: freePlan.monthly_credits })
              .eq("user_id", profile.id);

            logStep("User downgraded to free plan", { userId: profile.id });

            // Send cancellation email
            if (profile.email) {
              await sendEmailNotification(supabaseUrl, supabaseServiceKey, profile.email, "subscription_canceled", {
                user_name: profile.display_name || profile.email.split("@")[0],
                previous_plan: previousPlanName,
                resubscribe_url: `${origin}/subscription`,
              });
            }
          }
        } else {
          logStep("No user found for customer", { customerId });
        }
        break;
      }

      // ==================== INVOICE PAYMENT SUCCEEDED ====================
      case "invoice.payment_succeeded": {
        const invoice = event.data.object as Stripe.Invoice;
        const customerId = invoice.customer as string;
        const amount = invoice.amount_paid / 100;
        const currency = invoice.currency?.toUpperCase() || "USD";
        
        logStep("Invoice payment succeeded", { 
          invoiceId: invoice.id, 
          amount,
          currency 
        });

        // For recurring payments, update subscription period
        if (invoice.subscription) {
          const { data: profile } = await supabase
            .from("profiles")
            .select("id, email, display_name")
            .eq("stripe_customer_id", customerId)
            .single();

          if (profile) {
            // Get the subscription from Stripe to update period dates
            const subscription = await stripe.subscriptions.retrieve(invoice.subscription as string);
            
            await supabase
              .from("user_subscriptions")
              .update({
                status: "active",
                current_period_start: new Date(subscription.current_period_start * 1000).toISOString(),
                current_period_end: new Date(subscription.current_period_end * 1000).toISOString(),
              })
              .eq("user_id", profile.id);

            // Reset monthly credits on renewal
            const { data: userSub } = await supabase
              .from("user_subscriptions")
              .select("plan_id, subscription_plans(name)")
              .eq("user_id", profile.id)
              .single();

            if (userSub) {
              const { data: plan } = await supabase
                .from("subscription_plans")
                .select("monthly_credits, name")
                .eq("id", userSub.plan_id)
                .single();

              if (plan) {
                await supabase
                  .from("user_credits")
                  .update({
                    monthly_credits: plan.monthly_credits,
                    credits_reset_at: new Date(subscription.current_period_end * 1000).toISOString(),
                  })
                  .eq("user_id", profile.id);

                logStep("Credits renewed on payment", { userId: profile.id, credits: plan.monthly_credits });

                // Send payment success email for recurring payments
                if (profile.email) {
                  await sendEmailNotification(supabaseUrl, supabaseServiceKey, profile.email, "payment_successful", {
                    user_name: profile.display_name || profile.email.split("@")[0],
                    amount: `$${amount.toFixed(2)} ${currency}`,
                    description: `${plan.name} subscription renewal`,
                    date: new Date().toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }),
                  });
                }
              }
            }
          }
        }
        break;
      }

      // ==================== INVOICE PAYMENT FAILED ====================
      case "invoice.payment_failed": {
        const invoice = event.data.object as Stripe.Invoice;
        const customerId = invoice.customer as string;
        const amount = (invoice.amount_due || 0) / 100;
        const currency = invoice.currency?.toUpperCase() || "USD";
        
        logStep("Invoice payment failed", { 
          invoiceId: invoice.id, 
          attemptCount: invoice.attempt_count 
        });

        const { data: profile } = await supabase
          .from("profiles")
          .select("id, email, display_name")
          .eq("stripe_customer_id", customerId)
          .single();

        if (profile) {
          await supabase
            .from("user_subscriptions")
            .update({ status: "past_due" })
            .eq("user_id", profile.id);

          logStep("Subscription marked as past_due", { userId: profile.id });

          // Send payment failed email
          if (profile.email) {
            await sendEmailNotification(supabaseUrl, supabaseServiceKey, profile.email, "payment_failed", {
              user_name: profile.display_name || profile.email.split("@")[0],
              amount: `$${amount.toFixed(2)} ${currency}`,
              attempt_count: String(invoice.attempt_count || 1),
              date: new Date().toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" }),
              update_url: `${origin}/subscription`,
            });
          }
        }
        break;
      }

      // ==================== INVOICE UPCOMING ====================
      case "invoice.upcoming": {
        const invoice = event.data.object as Stripe.Invoice;
        logStep("Upcoming invoice", { 
          customerId: invoice.customer,
          amount: (invoice.amount_due || 0) / 100 
        });
        // Could be used to send reminder emails
        break;
      }

      default:
        logStep("Unhandled event type", { type: event.type });
    }

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

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

    // Log failed processing
    await logWebhookEvent(supabase, "stripe", eventType, eventId, "failed", { type: eventType, id: eventId }, 400, message, startTime);

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