import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { requireSupabaseAuth } from "@/integrations/supabase/auth-middleware";
import { analyzePhoto, generateLook, renderLookImage } from "./imisi.server";
import { FREE_RECOMMENDATIONS } from "./imisi";

export const analyzeStyleProfile = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((data: unknown) =>
    z
      .object({
        frontImage: z.string().min(20),
        sideImage: z.string().min(20).nullable().optional(),
        gender: z.string().nullable().optional(),
        name: z.string().nullable().optional(),
      })
      .parse(data),
  )
  .handler(async ({ data, context }) => {
    const analysis = await analyzePhoto({
      frontImage: data.frontImage,
      sideImage: data.sideImage ?? null,
      gender: data.gender ?? null,
      name: data.name ?? null,
    });

    const { error } = await context.supabase.from("style_profiles").upsert(
      {
        user_id: context.userId,
        body_shape: analysis.body_shape,
        face_shape: analysis.face_shape,
        skin_tone: analysis.skin_tone,
        undertone: analysis.undertone,
        proportions: analysis.proportions,
        height: analysis.height,
        observations: analysis.observations,
        confirmed: false,
      },
      { onConflict: "user_id" },
    );
    if (error) throw new Error(error.message);

    return analysis;
  });

export const createRecommendation = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((data: unknown) =>
    z
      .object({
        occasion: z.string().min(2),
        weather: z.string().nullable().optional(),
        timeOfDay: z.string().nullable().optional(),
        location: z.string().nullable().optional(),
        dressCode: z.string().nullable().optional(),
        notes: z.string().max(600).nullable().optional(),
        wantsHair: z.boolean().default(false),
        wantsMakeup: z.boolean().default(false),
      })
      .parse(data),
  )
  .handler(async ({ data, context }) => {
    const { supabase, userId } = context;

    const { data: profile, error: profileError } = await supabase
      .from("profiles")
      .select("*")
      .eq("id", userId)
      .maybeSingle();
    if (profileError) throw new Error(profileError.message);
    if (!profile) throw new Error("Finish onboarding before requesting a look.");
    if (profile.recommendations_used >= FREE_RECOMMENDATIONS) {
      throw new Error("You've used all 3 free styling sessions. Join the Premium waitlist for unlimited styling.");
    }

    const { data: analysis } = await supabase
      .from("style_profiles")
      .select("*")
      .eq("user_id", userId)
      .maybeSingle();

    const { data: past } = await supabase
      .from("recommendations")
      .select("title")
      .eq("user_id", userId)
      .order("created_at", { ascending: false })
      .limit(5);

    const payload = await generateLook({
      context: {
        occasion: data.occasion,
        weather: data.weather ?? null,
        timeOfDay: data.timeOfDay ?? null,
        location: data.location ?? null,
        dressCode: data.dressCode ?? null,
        notes: data.notes ?? null,
        wantsHair: data.wantsHair,
        wantsMakeup: data.wantsMakeup,
      },
      profile: {
        display_name: profile.display_name,
        gender: profile.gender,
        goals: profile.goals ?? [],
        perceptions: profile.perceptions ?? [],
        styles: profile.styles ?? [],
        discover_style: profile.discover_style,
      },
      analysis: analysis
        ? {
            body_shape: analysis.body_shape ?? "",
            face_shape: analysis.face_shape ?? "",
            skin_tone: analysis.skin_tone ?? "",
            undertone: analysis.undertone ?? "",
            proportions: analysis.proportions ?? "",
            height: analysis.height ?? "",
            observations: analysis.observations ?? [],
          }
        : null,
      history: (past ?? []).map((row) => row.title ?? "").filter(Boolean),
    });

    const imagePath = await renderLookImage(supabase, userId, payload.visual_prompt, {
      photoPath: profile.photo_path,
      sidePhotoPath: profile.side_photo_path,
    });

    const { data: inserted, error: insertError } = await supabase
      .from("recommendations")
      .insert({
        user_id: userId,
        title: payload.title,
        occasion: data.occasion,
        weather: data.weather ?? null,
        time_of_day: data.timeOfDay ?? null,
        location: data.location ?? null,
        dress_code: data.dressCode ?? null,
        notes: data.notes ?? null,
        payload: JSON.parse(JSON.stringify(payload)),
        image_path: imagePath,
      })
      .select("id")
      .single();
    if (insertError) throw new Error(insertError.message);

    await supabase
      .from("profiles")
      .update({ recommendations_used: profile.recommendations_used + 1 })
      .eq("id", userId);

    return { id: inserted.id };
  });
