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, x-supabase-client-platform, x-supabase-client-platform-version, x-supabase-client-runtime, x-supabase-client-runtime-version",
};

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

  try {
    const authHeader = req.headers.get("Authorization");
    if (!authHeader) {
      return new Response(JSON.stringify({ error: "Unauthorized" }), {
        status: 401,
        headers: { ...corsHeaders, "Content-Type": "application/json" },
      });
    }

    const supabaseUrl = Deno.env.get("SUPABASE_URL")!;
    const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!;
    const supabaseAnon = Deno.env.get("SUPABASE_ANON_KEY")!;

    // Verify user using explicit token
    const token = authHeader.replace("Bearer ", "");
    const anonClient = createClient(supabaseUrl, supabaseAnon);
    const {
      data: { user },
      error: authError,
    } = await anonClient.auth.getUser(token);

    if (authError || !user) {
      return new Response(JSON.stringify({ error: "Unauthorized" }), {
        status: 401,
        headers: { ...corsHeaders, "Content-Type": "application/json" },
      });
    }

    const { buildId, downloadUrl, platform } = await req.json();
    if (!buildId || !downloadUrl) {
      return new Response(
        JSON.stringify({ error: "buildId and downloadUrl are required" }),
        {
          status: 400,
          headers: { ...corsHeaders, "Content-Type": "application/json" },
        }
      );
    }

    // Get Appetize API key from api_configurations (admin-configured)
    const adminClient = createClient(supabaseUrl, supabaseServiceKey);
    const { data: apiConfig } = await adminClient
      .from("api_configurations")
      .select("id, config, usage_count")
      .eq("provider", "appetize")
      .eq("is_active", true)
      .limit(1)
      .maybeSingle();

    if (!apiConfig) {
      return new Response(
        JSON.stringify({
          error:
            "Appetize.io is not configured. Admin must add an Appetize API key in Admin > API Configuration.",
        }),
        {
          status: 400,
          headers: { ...corsHeaders, "Content-Type": "application/json" },
        }
      );
    }

    const appetizeApiKey = (apiConfig.config as Record<string, string>)
      ?.api_key;
    if (!appetizeApiKey) {
      return new Response(
        JSON.stringify({
          error:
            "Appetize API key not found in configuration. Admin must set the api_key in the config.",
        }),
        {
          status: 400,
          headers: { ...corsHeaders, "Content-Type": "application/json" },
        }
      );
    }

    // Upload to Appetize.io v1 API with retry and per-request timeout
    const cfg = apiConfig.config as Record<string, string>;
    const configuredTimeout = Number(cfg?.timeout_seconds);
    const configuredRetries = Number(cfg?.max_retries);
    const MAX_RETRIES = configuredRetries > 0 && configuredRetries <= 10 ? configuredRetries : 3;
    const RETRY_DELAYS = [2000, 5000, 10000];
    const FETCH_TIMEOUT_MS = (configuredTimeout > 0 ? configuredTimeout : 30) * 1000;
    let appetizeResponse: Response | null = null;
    let lastError = "";

    for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);

      try {
        appetizeResponse = await fetch("https://api.appetize.io/v1/apps", {
          method: "POST",
          headers: {
            "X-API-KEY": appetizeApiKey,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            url: downloadUrl,
            platform: platform === "ios" ? "ios" : "android",
          }),
          signal: controller.signal,
        });

        // Don't retry on client errors (4xx) — only on server/network errors
        if (appetizeResponse.ok || (appetizeResponse.status >= 400 && appetizeResponse.status < 500)) {
          break;
        }

        lastError = await appetizeResponse.text();
        console.warn(`Appetize attempt ${attempt + 1}/${MAX_RETRIES} failed (${appetizeResponse.status}): ${lastError}`);
      } catch (fetchError) {
        const isTimeout = fetchError instanceof DOMException && fetchError.name === "AbortError";
        lastError = isTimeout ? `Request timed out after ${FETCH_TIMEOUT_MS}ms` : (fetchError instanceof Error ? fetchError.message : String(fetchError));
        console.warn(`Appetize attempt ${attempt + 1}/${MAX_RETRIES} ${isTimeout ? "timeout" : "network error"}: ${lastError}`);
      } finally {
        clearTimeout(timeoutId);
      }

      if (attempt < MAX_RETRIES - 1) {
        await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt]));
      }
    }

    if (!appetizeResponse || !appetizeResponse.ok) {
      const errorText = appetizeResponse ? await appetizeResponse.text().catch(() => lastError) : lastError;
      console.error("Appetize API error after retries:", errorText);
      return new Response(
        JSON.stringify({
          error: `Appetize upload failed after ${MAX_RETRIES} attempts`,
          details: errorText,
        }),
        {
          status: 500,
          headers: { ...corsHeaders, "Content-Type": "application/json" },
        }
      );
    }

    const appetizeData = await appetizeResponse.json();
    const publicKey =
      appetizeData.publicKey ||
      appetizeData.data?.publicKey ||
      appetizeData.appVersions?.[0]?.publicKey;

    if (!publicKey) {
      console.error("Appetize response:", JSON.stringify(appetizeData));
      return new Response(
        JSON.stringify({ error: "No public key returned from Appetize" }),
        {
          status: 500,
          headers: { ...corsHeaders, "Content-Type": "application/json" },
        }
      );
    }

    // Get existing build config so we can merge (not overwrite)
    const { data: existingBuild } = await adminClient
      .from("app_builds")
      .select("config")
      .eq("id", buildId)
      .single();

    const existingConfig =
      (existingBuild?.config as Record<string, unknown>) || {};

    // Merge appetize keys into existing config
    await adminClient
      .from("app_builds")
      .update({
        config: {
          ...existingConfig,
          appetize_public_key: publicKey,
          appetize_preview_url: `https://appetize.io/app/${publicKey}`,
        },
      })
      .eq("id", buildId);

    // Update usage count
    await adminClient
      .from("api_configurations")
      .update({
        usage_count: (apiConfig.usage_count || 0) + 1,
        last_used_at: new Date().toISOString(),
      })
      .eq("id", apiConfig.id);

    return new Response(
      JSON.stringify({
        success: true,
        publicKey,
        previewUrl: `https://appetize.io/app/${publicKey}`,
      }),
      { headers: { ...corsHeaders, "Content-Type": "application/json" } }
    );
  } catch (error) {
    console.error("Appetize upload error:", error);
    return new Response(
      JSON.stringify({
        error: error instanceof Error ? error.message : "Unknown error",
      }),
      {
        status: 500,
        headers: { ...corsHeaders, "Content-Type": "application/json" },
      }
    );
  }
});
