/**
 * Polderfest Tool-Calling demo — reference snippets (AI SDK v6)
 * --------------------------------------------------
 * Dit zijn de tools die we live opbouwen tijdens Les 12.
 * Matcht met de actuele stack van polderfest-demo:
 *   - ai@^6
 *   - @ai-sdk/openai@^3
 *   - @ai-sdk/react@^3
 *
 * Gebruik dit als naslag — niet 1-op-1 kopiëren tijdens demo.
 * Plek in project: app/api/chat/route.ts
 */

import {
  convertToModelMessages,
  stepCountIs,
  streamText,
  tool,
  type UIMessage,
} from "ai";
import { openai } from "@ai-sdk/openai";
import { createClient } from "@supabase/supabase-js";
import { z } from "zod";

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseKey =
  process.env.SUPABASE_SERVICE_ROLE_KEY ??
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
const supabase = createClient(supabaseUrl, supabaseKey);

// ────────────────────────────────────────────────────────────
// Tool 1: searchBands — filter op velden
// ────────────────────────────────────────────────────────────
const searchBands = tool({
  description:
    "Zoek bands in de Polderfest line-up. Filter op dag, stage, genre of tier. " +
    "Gebruik dit als de gebruiker iets zoekt op één of meerdere criteria.",
  inputSchema: z.object({
    day: z
      .enum(["Vrijdag", "Zaterdag", "Zondag"])
      .optional()
      .describe("Festival-dag"),
    stage: z
      .string()
      .optional()
      .describe("Bv. Main Stage, Tent Stage, Beach Stage, Acoustic Bar, Late Night Tent"),
    genre: z
      .string()
      .optional()
      .describe("Bv. Indie Rock, Electronic, Hip-Hop, Jazz Fusion"),
    tier: z.enum(["headliner", "mid", "opener"]).optional(),
    minPopularity: z
      .number()
      .min(1)
      .max(100)
      .optional()
      .describe("Minimale populariteit (1-100)"),
  }),
  execute: async ({ day, stage, genre, tier, minPopularity }) => {
    let q = supabase
      .from("bands")
      .select(
        "id, name, genre, sub_genre, stage, day, start_time, " +
          "origin_city, tier, popularity, bio",
      );
    if (day) q = q.eq("day", day);
    if (stage) q = q.eq("stage", stage);
    if (genre) q = q.eq("genre", genre);
    if (tier) q = q.eq("tier", tier);
    if (minPopularity) q = q.gte("popularity", minPopularity);

    const { data, error } = await q.limit(20);
    if (error) return { error: error.message };
    return { count: data.length, bands: data };
  },
});

// ────────────────────────────────────────────────────────────
// Tool 2: getBandByName — exacte lookup
// ────────────────────────────────────────────────────────────
const getBandByName = tool({
  description:
    "Haal alle details op van één specifieke band, inclusief members en bio. " +
    "Gebruik dit als de gebruiker naar een specifieke band vraagt.",
  inputSchema: z.object({
    name: z.string().describe("Exacte band-naam"),
  }),
  execute: async ({ name }) => {
    const { data, error } = await supabase
      .from("bands")
      .select("*")
      .ilike("name", name)
      .single();
    if (error) return { error: `Band '${name}' niet gevonden.` };
    return data;
  },
});

// ────────────────────────────────────────────────────────────
// Tool 3: getStats — aggregate over alle bands
// ────────────────────────────────────────────────────────────
const getStats = tool({
  description:
    "Geef statistieken over de festival-line-up — totaal aantal bands, " +
    "verdeling per genre, per dag, of per stage. Geen filters — overzicht.",
  inputSchema: z.object({
    groupBy: z
      .enum(["genre", "day", "stage", "tier"])
      .describe("Hoe te groeperen"),
  }),
  execute: async ({ groupBy }) => {
    const { data, error } = await supabase.from("bands").select(groupBy);
    if (error) return { error: error.message };

    const counts: Record<string, number> = {};
    for (const row of data) {
      const key = row[groupBy as keyof typeof row] as string;
      counts[key] = (counts[key] ?? 0) + 1;
    }
    return { total: data.length, counts };
  },
});

// ────────────────────────────────────────────────────────────
// Tool 4: getScheduleByDay — slot-overzicht
// ────────────────────────────────────────────────────────────
const getScheduleByDay = tool({
  description:
    "Geef het volledige tijdschema voor één festival-dag. " +
    "Bands gesorteerd op tijdslot. Handig voor 'wat speelt er om 22:00?'",
  inputSchema: z.object({
    day: z.enum(["Vrijdag", "Zaterdag", "Zondag"]),
    stage: z
      .string()
      .optional()
      .describe("Optioneel filteren op specifieke stage"),
  }),
  execute: async ({ day, stage }) => {
    let q = supabase
      .from("bands")
      .select("name, stage, start_time, duration_min, tier")
      .eq("day", day);
    if (stage) q = q.eq("stage", stage);
    const { data, error } = await q.order("start_time", { ascending: true });
    if (error) return { error: error.message };
    return data;
  },
});

// ────────────────────────────────────────────────────────────
// Tool 5 (write): addFavorite — user_favorites tabel
// ────────────────────────────────────────────────────────────
const addFavorite = tool({
  description:
    "Voeg een band toe aan de favorieten van de gebruiker. " +
    "Gebruik alleen als de gebruiker expliciet vraagt 'voeg X toe aan mijn favorieten'.",
  inputSchema: z.object({
    userEmail: z.string().email().describe("Email van de gebruiker"),
    bandName: z.string().describe("Exacte band-naam"),
  }),
  execute: async ({ userEmail, bandName }) => {
    const { data: band } = await supabase
      .from("bands")
      .select("id")
      .ilike("name", bandName)
      .single();
    if (!band) return { error: `Band '${bandName}' niet gevonden.` };

    const { error } = await supabase
      .from("user_favorites")
      .insert({ user_email: userEmail, band_id: band.id });
    if (error) return { error: error.message };
    return { success: true, bandName, bandId: band.id };
  },
});

// ────────────────────────────────────────────────────────────
// Tool 6 (read): listFavorites
// ────────────────────────────────────────────────────────────
const listFavorites = tool({
  description: "Geef de favoriete bands van de gebruiker.",
  inputSchema: z.object({
    userEmail: z.string().email(),
  }),
  execute: async ({ userEmail }) => {
    const { data, error } = await supabase
      .from("user_favorites")
      .select("bands(name, genre, day, start_time, stage)")
      .eq("user_email", userEmail);
    if (error) return { error: error.message };
    return data?.map((r) => r.bands) ?? [];
  },
});

// ────────────────────────────────────────────────────────────
// De chat-route met alle tools
// ────────────────────────────────────────────────────────────
export async function POST(req: Request) {
  try {
    const { messages }: { messages: UIMessage[] } = await req.json();

    const system = `Je bent een festival-assistent voor Polderfest 2027.
Je hebt toegang tot tools om de bands-database te bevragen. Gebruik altijd
tools voor concrete vragen — verzin nooit data. Antwoord beknopt en in
het Nederlands.

Tips:
- Voor "welke bands op X?" → searchBands
- Voor specifieke band → getBandByName
- Voor "hoeveel" / "verdeling" → getStats
- Voor tijdschema → getScheduleByDay
- Voor favorieten → addFavorite / listFavorites

Als een tool een error returnt, leg dat netjes uit aan de gebruiker.`;

    const result = streamText({
      model: openai("gpt-4o-mini"),
      system,
      messages: await convertToModelMessages(messages),
      tools: {
        searchBands,
        getBandByName,
        getStats,
        getScheduleByDay,
        addFavorite,
        listFavorites,
      },
      stopWhen: stepCountIs(5),
    });

    return result.toUIMessageStreamResponse({
      onError(error: unknown) {
        if (error == null) return "unknown error";
        if (typeof error === "string") return error;
        if (error instanceof Error) return error.message;
        return JSON.stringify(error);
      },
    });
  } catch (err) {
    const message = err instanceof Error ? err.message : "Unknown error";
    return Response.json(
      { error: "Chat route failed", details: message },
      { status: 500 },
    );
  }
}
