import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react/schema";
import { shadcnComponentDefinitions } from "@json-render/shadcn/catalog";
import { z } from "zod";

// =============================================================================
// Shared 3D schemas
// =============================================================================

const vec3 = z.array(z.number());

const animation3D = z
  .object({
    rotate: vec3.nullable(),
  })
  .nullable();

const transform3DProps = {
  position: vec3.nullable(),
  rotation: vec3.nullable(),
  scale: vec3.nullable(),
};

const material3DProps = {
  color: z.string().nullable(),
  metalness: z.number().nullable(),
  roughness: z.number().nullable(),
  emissive: z.string().nullable(),
  emissiveIntensity: z.number().nullable(),
  wireframe: z.boolean().nullable(),
  opacity: z.number().nullable(),
};

const mesh3DProps = {
  ...transform3DProps,
  ...material3DProps,
  args: z.array(z.number()).nullable(),
  animation: animation3D,
};

/**
 * json-render + AI SDK Example Catalog
 *
 * Components for rendering data dashboards generated by the ToolLoopAgent.
 * Data flows in through tools (weather, GitHub, crypto, HN), not user actions.
 */
export const explorerCatalog = defineCatalog(schema, {
  components: {
    // From @json-render/shadcn (used as-is)
    Stack: shadcnComponentDefinitions.Stack,
    Card: shadcnComponentDefinitions.Card,
    Grid: shadcnComponentDefinitions.Grid,
    Heading: shadcnComponentDefinitions.Heading,
    Separator: shadcnComponentDefinitions.Separator,
    Accordion: shadcnComponentDefinitions.Accordion,
    Progress: shadcnComponentDefinitions.Progress,
    Skeleton: shadcnComponentDefinitions.Skeleton,
    Badge: shadcnComponentDefinitions.Badge,
    Alert: shadcnComponentDefinitions.Alert,

    // Chat-specific components (different schemas or fully custom)
    Text: {
      props: z.object({
        content: z.string(),
        muted: z.boolean().nullable(),
      }),
      description: "Text content",
      example: { content: "Here is your data overview." },
    },

    Metric: {
      props: z.object({
        label: z.string(),
        value: z.string(),
        detail: z.string().nullable(),
        trend: z.enum(["up", "down", "neutral"]).nullable(),
      }),
      description:
        "Single metric display with label, value, and optional trend indicator",
      example: {
        label: "Temperature",
        value: "72F",
        detail: "Feels like 68F",
        trend: "up",
      },
    },

    Table: {
      props: z.object({
        data: z.array(z.record(z.string(), z.unknown())),
        columns: z.array(
          z.object({
            key: z.string(),
            label: z.string(),
          }),
        ),
        emptyMessage: z.string().nullable(),
      }),
      description:
        'Data table. Use { "$state": "/path" } to bind read-only data from state.',
      example: {
        data: { $state: "/stories" },
        columns: [
          { key: "title", label: "Title" },
          { key: "score", label: "Score" },
        ],
      },
    },

    Link: {
      props: z.object({
        text: z.string(),
        href: z.string(),
      }),
      description: "External link that opens in a new tab",
      example: { text: "View on GitHub", href: "https://github.com" },
    },

    // Charts
    BarChart: {
      props: z.object({
        title: z.string().nullable(),
        data: z.array(z.record(z.string(), z.unknown())),
        xKey: z.string(),
        yKey: z.string(),
        aggregate: z.enum(["sum", "count", "avg"]).nullable(),
        color: z.string().nullable(),
        height: z.number().nullable(),
      }),
      description:
        'Bar chart visualization. Use { "$state": "/path" } to bind read-only data. xKey is the category field, yKey is the numeric value field.',
    },

    LineChart: {
      props: z.object({
        title: z.string().nullable(),
        data: z.array(z.record(z.string(), z.unknown())),
        xKey: z.string(),
        yKey: z.string(),
        aggregate: z.enum(["sum", "count", "avg"]).nullable(),
        color: z.string().nullable(),
        height: z.number().nullable(),
      }),
      description:
        'Line chart visualization. Use { "$state": "/path" } to bind read-only data. xKey is the x-axis field, yKey is the numeric value field.',
    },

    // Interactive
    Tabs: {
      props: z.object({
        defaultValue: z.string().nullable(),
        tabs: z.array(
          z.object({
            value: z.string(),
            label: z.string(),
          }),
        ),
      }),
      slots: ["default"],
      description: "Tabbed content container",
    },

    TabContent: {
      props: z.object({
        value: z.string(),
      }),
      slots: ["default"],
      description: "Content for a specific tab",
    },

    // Educational / Rich content
    Callout: {
      props: z.object({
        type: z.enum(["info", "tip", "warning", "important"]).nullable(),
        title: z.string().nullable(),
        content: z.string(),
      }),
      description:
        "Highlighted callout box for tips, warnings, notes, or key information",
      example: {
        type: "tip",
        title: "Did you know?",
        content: "The sun is about 93 million miles from Earth.",
      },
    },

    Timeline: {
      props: z.object({
        items: z.array(
          z.object({
            title: z.string(),
            description: z.string().nullable(),
            date: z.string().nullable(),
            status: z.enum(["completed", "current", "upcoming"]).nullable(),
          }),
        ),
      }),
      description:
        "Vertical timeline showing ordered events, steps, or historical milestones",
      example: {
        items: [
          {
            title: "Discovery",
            description: "Initial breakthrough",
            date: "1905",
            status: "completed",
          },
        ],
      },
    },

    PieChart: {
      props: z.object({
        title: z.string().nullable(),
        data: z.array(z.record(z.string(), z.unknown())),
        nameKey: z.string(),
        valueKey: z.string(),
        height: z.number().nullable(),
      }),
      description:
        'Pie/donut chart for proportional data. Use { "$state": "/path" } to bind read-only data. nameKey is the label field, valueKey is the numeric value field.',
    },

    // Interactive / Input
    RadioGroup: {
      props: z.object({
        label: z.string().nullable(),
        value: z.string().nullable(),
        options: z.array(
          z.object({
            value: z.string(),
            label: z.string(),
          }),
        ),
      }),
      description:
        'Radio button group for single selection. Use { "$bindState": "/path" } for two-way binding. Use for multiple-choice questions, settings, or any single-select input.',
      example: {
        label: "Choose one",
        value: { $bindState: "/answer" },
        options: [
          { value: "a", label: "Option A" },
          { value: "b", label: "Option B" },
        ],
      },
    },

    SelectInput: {
      props: z.object({
        label: z.string().nullable(),
        value: z.string().nullable(),
        placeholder: z.string().nullable(),
        options: z.array(
          z.object({
            value: z.string(),
            label: z.string(),
          }),
        ),
      }),
      description:
        'Dropdown select input. Use { "$bindState": "/path" } for two-way binding. Use when there are many options and a dropdown is more compact than radio buttons.',
      example: {
        label: "Country",
        value: { $bindState: "/selectedCountry" },
        placeholder: "Select a country",
        options: [
          { value: "us", label: "United States" },
          { value: "uk", label: "United Kingdom" },
        ],
      },
    },

    TextInput: {
      props: z.object({
        label: z.string().nullable(),
        value: z.string().nullable(),
        placeholder: z.string().nullable(),
        type: z.enum(["text", "email", "number", "password", "url"]).nullable(),
      }),
      description:
        'Text input field. Use { "$bindState": "/path" } for two-way binding. Use for free-text entry like names, emails, search, etc.',
      example: {
        label: "Your name",
        value: { $bindState: "/userName" },
        placeholder: "Enter your name",
        type: "text",
      },
    },

    Button: {
      props: z.object({
        label: z.string(),
        variant: z
          .enum(["default", "secondary", "destructive", "outline", "ghost"])
          .nullable(),
        size: z.enum(["default", "sm", "lg"]).nullable(),
        disabled: z.boolean().nullable(),
      }),
      description:
        "Clickable button. Use with on.press to trigger actions like setState, pushState, etc. Can be used for quiz submissions, form actions, navigation, and more.",
      example: {
        label: "Submit",
        variant: "default",
        size: "default",
        disabled: null,
      },
    },

    // =========================================================================
    // 3D Scene Components (React Three Fiber)
    // =========================================================================

    // Containers
    Scene3D: {
      props: z.object({
        height: z.string().nullable(),
        background: z.string().nullable(),
        cameraPosition: vec3.nullable(),
        cameraFov: z.number().nullable(),
        autoRotate: z.boolean().nullable(),
      }),
      slots: ["default"],
      description:
        "3D scene container with orbit controls. All 3D components (Sphere, Box, lights, etc.) must be children of a Scene3D. height is a CSS value like '500px'.",
      example: {
        height: "500px",
        background: "#000010",
        cameraPosition: [0, 25, 45],
        cameraFov: null,
        autoRotate: null,
      },
    },

    Group3D: {
      props: z.object({
        ...transform3DProps,
        animation: animation3D,
      }),
      slots: ["default"],
      description:
        "3D group for positioning, rotating, and animating children together. Use to create orbits: position a planet inside a Group3D and animate the group's rotation.",
      example: {
        position: null,
        rotation: null,
        scale: null,
        animation: { rotate: [0, 0.005, 0] },
      },
    },

    // Geometry primitives
    Box: {
      props: z.object(mesh3DProps),
      description:
        "3D box/cube mesh. args: [width, height, depth]. Supports on.press for click interaction.",
      example: {
        position: [0, 0, 0],
        color: "#4488ff",
        args: [1, 1, 1],
      },
    },

    Sphere: {
      props: z.object(mesh3DProps),
      description:
        "3D sphere mesh. args: [radius, widthSegments, heightSegments]. Use higher segment counts (32+) for smooth spheres.",
      example: {
        position: [0, 0, 0],
        color: "#4B7BE5",
        args: [1, 32, 32],
      },
    },

    Cylinder: {
      props: z.object(mesh3DProps),
      description:
        "3D cylinder mesh. args: [radiusTop, radiusBottom, height, radialSegments].",
      example: {
        position: [0, 0, 0],
        color: "#88aa44",
        args: [1, 1, 2, 32],
      },
    },

    Cone: {
      props: z.object(mesh3DProps),
      description: "3D cone mesh. args: [radius, height, radialSegments].",
      example: {
        position: [0, 0, 0],
        color: "#ff8844",
        args: [1, 2, 32],
      },
    },

    Torus: {
      props: z.object(mesh3DProps),
      description:
        "3D torus (donut) mesh. args: [radius, tube, radialSegments, tubularSegments].",
      example: {
        position: [0, 0, 0],
        color: "#aa44ff",
        args: [1, 0.4, 16, 100],
      },
    },

    Plane: {
      props: z.object(mesh3DProps),
      description:
        "3D flat plane mesh. args: [width, height]. Useful for ground planes or flat surfaces.",
      example: {
        position: [0, -1, 0],
        rotation: [-Math.PI / 2, 0, 0],
        color: "#334455",
        args: [10, 10],
      },
    },

    Ring: {
      props: z.object(mesh3DProps),
      description:
        "3D flat ring mesh. args: [innerRadius, outerRadius, thetaSegments]. Great for orbit path indicators.",
      example: {
        position: [0, 0, 0],
        rotation: [-Math.PI / 2, 0, 0],
        color: "#ffffff",
        opacity: 0.2,
        args: [14.8, 15.2, 64],
      },
    },

    // Lights
    AmbientLight: {
      props: z.object({
        color: z.string().nullable(),
        intensity: z.number().nullable(),
      }),
      description:
        "Ambient light that illuminates all objects equally. Use for base scene illumination.",
      example: { color: null, intensity: 0.3 },
    },

    PointLight: {
      props: z.object({
        position: vec3.nullable(),
        color: z.string().nullable(),
        intensity: z.number().nullable(),
        distance: z.number().nullable(),
      }),
      description:
        "Point light that emits from a position in all directions. Use for suns, lamps, etc.",
      example: { position: [0, 0, 0], intensity: 2 },
    },

    DirectionalLight: {
      props: z.object({
        position: vec3.nullable(),
        color: z.string().nullable(),
        intensity: z.number().nullable(),
      }),
      description:
        "Directional light like sunlight. Position sets direction, not location.",
      example: { position: [5, 10, 5], intensity: 1 },
    },

    // Helpers (drei)
    Stars: {
      props: z.object({
        radius: z.number().nullable(),
        depth: z.number().nullable(),
        count: z.number().nullable(),
        factor: z.number().nullable(),
        fade: z.boolean().nullable(),
        speed: z.number().nullable(),
      }),
      description:
        "Starfield background for space scenes. Renders thousands of tiny points around the scene.",
      example: { count: 5000, fade: true },
    },

    Label3D: {
      props: z.object({
        text: z.string(),
        position: vec3.nullable(),
        rotation: vec3.nullable(),
        color: z.string().nullable(),
        fontSize: z.number().nullable(),
        anchorX: z.enum(["left", "center", "right"]).nullable(),
        anchorY: z.enum(["top", "middle", "bottom"]).nullable(),
      }),
      description:
        "Text label rendered in 3D space. Always faces the camera (billboard). Use for labeling objects in a scene.",
      example: {
        text: "Earth",
        position: [15, 2, 0],
        color: "#ffffff",
        fontSize: 0.8,
      },
    },
  },

  actions: {},
});
