import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { createClient } from "@supabase/supabase-js";
import { requireSupabaseAuth } from "@/integrations/supabase/auth-middleware";
import type { Database } from "@/integrations/supabase/types";

export interface PromptRow {
  id: string;
  title: string;
  prompt_text: string;
  category: string | null;
  emotion_tags: string[];
  personality_tags: string[];
  style_tags: string[];
  ai_tool: string;
  is_active: boolean;
  created_at: string;
}

const PromptInputSchema = z.object({
  title: z.string().trim().min(1).max(200),
  prompt_text: z.string().trim().min(1).max(8000),
  category: z.string().trim().max(100).optional().nullable(),
  emotion_tags: z.array(z.string().max(50)).max(20).default([]),
  personality_tags: z.array(z.string().max(50)).max(20).default([]),
  style_tags: z.array(z.string().max(50)).max(20).default([]),
  ai_tool: z.string().max(40).default("Any"),
  is_active: z.boolean().default(true),
});

function publicClient() {
  return createClient<Database>(
    process.env.SUPABASE_URL!,
    process.env.SUPABASE_PUBLISHABLE_KEY!,
    { auth: { persistSession: false, autoRefreshToken: false } },
  );
}

// PUBLIC: browse / filter active prompts
export const listPrompts = createServerFn({ method: "GET" })
  .inputValidator((d: unknown) =>
    z
      .object({
        q: z.string().optional(),
        category: z.string().optional(),
        emotion: z.string().optional(),
        personality: z.string().optional(),
        style: z.string().optional(),
        ai_tool: z.string().optional(),
        limit: z.number().int().min(1).max(500).default(200),
      })
      .parse(d ?? {}),
  )
  .handler(async ({ data }): Promise<PromptRow[]> => {
    const sb = publicClient();
    let q = sb
      .from("prompts")
      .select("id,title,prompt_text,category,emotion_tags,personality_tags,style_tags,ai_tool,is_active,created_at")
      .eq("is_active", true)
      .order("created_at", { ascending: false })
      .limit(data.limit);
    if (data.category) q = q.eq("category", data.category);
    if (data.ai_tool && data.ai_tool !== "Any") q = q.in("ai_tool", [data.ai_tool, "Any"]);
    if (data.emotion) q = q.contains("emotion_tags", [data.emotion]);
    if (data.personality) q = q.contains("personality_tags", [data.personality]);
    if (data.style) q = q.contains("style_tags", [data.style]);
    if (data.q) q = q.or(`title.ilike.%${data.q}%,prompt_text.ilike.%${data.q}%`);
    const { data: rows, error } = await q;
    if (error) throw new Error(error.message);
    return (rows ?? []) as PromptRow[];
  });

export const getPromptsByIds = createServerFn({ method: "POST" })
  .inputValidator((d: unknown) => z.object({ ids: z.array(z.string().uuid()).max(50) }).parse(d))
  .handler(async ({ data }): Promise<PromptRow[]> => {
    if (data.ids.length === 0) return [];
    const sb = publicClient();
    const { data: rows, error } = await sb
      .from("prompts")
      .select("id,title,prompt_text,category,emotion_tags,personality_tags,style_tags,ai_tool,is_active,created_at")
      .in("id", data.ids)
      .eq("is_active", true);
    if (error) throw new Error(error.message);
    return (rows ?? []) as PromptRow[];
  });

// AUTH: am I an admin?
export const getMyRoles = createServerFn({ method: "GET" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    const { data, error } = await context.supabase
      .from("user_roles" as never)
      .select("role")
      .eq("user_id", context.userId);
    if (error) throw new Error(error.message);
    const roles = ((data ?? []) as { role: string }[]).map((r) => r.role);
    return { roles, isAdmin: roles.includes("admin") };
  });

// AUTH: claim admin if no admin exists (bootstrap)
export const claimFirstAdmin = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }) => {
    const { data, error } = await context.supabase.rpc("claim_first_admin" as never);
    if (error) throw new Error(error.message);
    return { claimed: Boolean(data) };
  });

// ADMIN: helpers
async function assertAdmin(supabase: { rpc: (fn: string, args: unknown) => Promise<{ data: unknown; error: unknown }> }, userId: string) {
  const { data, error } = await supabase.rpc("has_role", { _user_id: userId, _role: "admin" });
  if (error) throw new Error((error as { message: string }).message);
  if (!data) throw new Error("Forbidden — admin only");
}

// ADMIN: create
export const createPrompt = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((d: unknown) => PromptInputSchema.parse(d))
  .handler(async ({ data, context }) => {
    await assertAdmin(context.supabase as never, context.userId);
    const { data: row, error } = await context.supabase
      .from("prompts")
      .insert({ ...data, created_by: context.userId })
      .select("id")
      .single();
    if (error) throw new Error(error.message);
    return { id: row.id };
  });

// ADMIN: update
export const updatePrompt = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((d: unknown) =>
    z.object({ id: z.string().uuid(), patch: PromptInputSchema.partial() }).parse(d),
  )
  .handler(async ({ data, context }) => {
    await assertAdmin(context.supabase as never, context.userId);
    const { error } = await context.supabase.from("prompts").update(data.patch).eq("id", data.id);
    if (error) throw new Error(error.message);
    return { ok: true };
  });

// ADMIN: delete
export const deletePrompt = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((d: unknown) => z.object({ id: z.string().uuid() }).parse(d))
  .handler(async ({ data, context }) => {
    await assertAdmin(context.supabase as never, context.userId);
    const { error } = await context.supabase.from("prompts").delete().eq("id", data.id);
    if (error) throw new Error(error.message);
    return { ok: true };
  });

// ADMIN: bulk import
export const bulkImportPrompts = createServerFn({ method: "POST" })
  .middleware([requireSupabaseAuth])
  .inputValidator((d: unknown) =>
    z.object({ prompts: z.array(PromptInputSchema).min(1).max(500) }).parse(d),
  )
  .handler(async ({ data, context }) => {
    await assertAdmin(context.supabase as never, context.userId);
    const rows = data.prompts.map((p) => ({ ...p, created_by: context.userId }));
    const { error, count } = await context.supabase
      .from("prompts")
      .insert(rows, { count: "exact" });
    if (error) throw new Error(error.message);
    return { inserted: count ?? rows.length };
  });

// ADMIN: list all (incl. inactive)
export const adminListPrompts = createServerFn({ method: "GET" })
  .middleware([requireSupabaseAuth])
  .handler(async ({ context }): Promise<PromptRow[]> => {
    await assertAdmin(context.supabase as never, context.userId);
    const { data, error } = await context.supabase
      .from("prompts")
      .select("id,title,prompt_text,category,emotion_tags,personality_tags,style_tags,ai_tool,is_active,created_at")
      .order("created_at", { ascending: false });
    if (error) throw new Error(error.message);
    return (data ?? []) as PromptRow[];
  });
