import { createServerFn } from "@tanstack/react-start";
import { requireSupabaseAuth } from "@/integrations/supabase/auth-middleware";
import { levelFor, scoreFromAnswers } from "./assessment";

/** Categories + questions + this user's saved answers, for the resumable flow. */
export const getAssessmentState = createServerFn({ method: "GET" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    const { supabase, userId } = context;

    const [categories, questions, responses] = await Promise.all([
      supabase
        .from("assessment_categories")
        .select("id, slug, code, name, description, sort_order")
        .order("sort_order", { ascending: true }),
      supabase
        .from("assessment_questions")
        .select("id, category_id, prompt, sort_order")
        .order("sort_order", { ascending: true }),
      supabase.from("assessment_responses").select("question_id, score").eq("user_id", userId),
    ]);


    if (categories.error) throw new Error(categories.error.message);
    if (questions.error) throw new Error(questions.error.message);
    if (responses.error) throw new Error(responses.error.message);

    return {
      categories: categories.data ?? [],
      questions: questions.data ?? [],
      answers: Object.fromEntries((responses.data ?? []).map((r) => [r.question_id, r.score])),
    };
  });

export const saveResponses = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((data: { answers: { question_id: string; score: number }[] }) => data)
  .handler(async ({ data, context }) => {
    const { supabase, userId } = context;
    const rows = data.answers
      .filter((a) => a.score >= 1 && a.score <= 5)
      .map((a) => ({ user_id: userId, question_id: a.question_id, score: a.score }));
    if (rows.length === 0) return { saved: 0 };
    const { error } = await supabase
      .from("assessment_responses")
      .upsert(rows, { onConflict: "user_id,question_id" });
    if (error) throw new Error(error.message);
    return { saved: rows.length };
  });

export const submitAssessment = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    const { supabase, userId } = context;

    // Free plan includes a single assessment and result.
    const [{ data: profile }, existing] = await Promise.all([
      supabase.from("profiles").select("plan_tier").eq("id", userId).maybeSingle(),
      supabase.from("assessment_results").select("id").eq("user_id", userId),
    ]);
    const tier = profile?.plan_tier ?? "free";
    if (tier === "free" && (existing.data?.length ?? 0) >= 1) {
      throw new Error(
        "Your free plan includes one assessment and result. Upgrade to Pro for unlimited assessments and your full action plan.",
      );
    }


    const [categories, questions, responses] = await Promise.all([
      supabase.from("assessment_categories").select("id, slug, name").order("sort_order"),
      supabase.from("assessment_questions").select("id, category_id"),
      supabase.from("assessment_responses").select("question_id, score").eq("user_id", userId),
    ]);
    if (categories.error) throw new Error(categories.error.message);
    if (questions.error) throw new Error(questions.error.message);
    if (responses.error) throw new Error(responses.error.message);

    const answerMap = new Map((responses.data ?? []).map((r) => [r.question_id, r.score]));
    const categoryScores: Record<string, number> = {};

    for (const cat of categories.data ?? []) {
      const answers = (questions.data ?? [])
        .filter((q) => q.category_id === cat.id)
        .map((q) => answerMap.get(q.id))
        .filter((s): s is number => typeof s === "number");
      categoryScores[cat.slug] = scoreFromAnswers(answers);
    }

    const values = Object.values(categoryScores);
    const overall = values.length
      ? Math.round(values.reduce((a, b) => a + b, 0) / values.length)
      : 0;
    const level = levelFor(overall);

    const { error } = await supabase.from("assessment_results").insert({
      user_id: userId,
      overall_score: overall,
      level,
      category_scores: categoryScores,
    });
    if (error) throw new Error(error.message);

    return { overall, level, categoryScores };
  });

/**
 * Latest result plus the UZIA recommendation engine output:
 * every domain scoring under 75 gets matched to catalogue courses through the
 * course_recommendations matrix (priority 1 = strongest fix).
 */
export const getMyResults = createServerFn({ method: "GET" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    const { supabase, userId } = context;

    const { data: profile } = await supabase
      .from("profiles")
      .select("plan_tier")
      .eq("id", userId)
      .maybeSingle();
    const isPro = profile?.plan_tier === "pro" || profile?.plan_tier === "team";

    const { data: result, error } = await supabase
      .from("assessment_results")
      .select("*")
      .eq("user_id", userId)
      .order("created_at", { ascending: false })
      .limit(1)
      .maybeSingle();
    if (error) throw new Error(error.message);

    const { data: categories, error: catError } = await supabase
      .from("assessment_categories")
      .select("slug, code, name, description, sort_order")
      .order("sort_order");
    if (catError) throw new Error(catError.message);

    if (!result)
      return {
        result: null,
        breakdown: [],
        weakest: [],
        pathway: [],
        recommended: [],
        isPro,
        lockedDomains: 0,
      };


    const scores = (result.category_scores ?? {}) as Record<string, number>;
    const breakdown = (categories ?? []).map((c) => ({
      slug: c.slug,
      code: c.code,
      name: c.name,
      description: c.description,
      score: scores[c.slug] ?? 0,
      level: levelFor(scores[c.slug] ?? 0),
    }));

    const weakest = [...breakdown].sort((a, b) => a.score - b.score).slice(0, 3);

    const { data: matrix, error: matrixError } = await supabase
      .from("course_recommendations")
      .select(
        "domain_code, min_score, max_score, priority, courses(id, slug, title, summary, category_slug, level, group_code, group_name, domain_code, credential_level, duration_weeks, learning_hours, price_kes)",
      )
      .order("priority", { ascending: true });
    if (matrixError) throw new Error(matrixError.message);

    // Domains needing action, most urgent first.
    const targets = breakdown.filter((b) => b.score < 75).sort((a, b) => a.score - b.score);

    const pathway = targets.map((domain) => {
      const matches = (matrix ?? [])
        .filter(
          (m) =>
            m.domain_code === domain.code &&
            domain.score >= m.min_score &&
            domain.score <= m.max_score,
        )
        .sort((a, b) => a.priority - b.priority);
      // Below 60 the recommendation is mandatory; 60-74 is a growth option.
      const limit = domain.score < 60 ? 2 : 1;
      return {
        domain,
        mandatory: domain.score < 60,
        courses: matches.slice(0, limit).flatMap((m) => (m.courses ? [m.courses] : [])),
      };
    });

    // Free plan sees the single most urgent step; the full action plan is Pro.
    const visiblePathway = isPro ? pathway : pathway.slice(0, 1);
    const recommended = isPro
      ? pathway.flatMap((p) => p.courses).slice(0, 6)
      : visiblePathway
          .flatMap((p) => p.courses)
          .filter((c) => c.credential_level === "Foundation")
          .slice(0, 3);

    return {
      result: {
        overall_score: Number(result.overall_score),
        level: result.level,
        created_at: result.created_at,
      },
      breakdown,
      weakest,
      pathway: visiblePathway,
      recommended,
      isPro,
      lockedDomains: isPro ? 0 : Math.max(0, pathway.length - visiblePathway.length),
    };

  });

