import { z } from "zod";
import type { db as prodDb } from "../../../db/index.ts";
import {
	createItem,
	deleteItem,
	getAllItems,
	getItemById,
	updateItem,
} from "../../services/item.service.ts";
import { withImageUrl, withImageUrls } from "../../services/storage.service.ts";

type Db = typeof prodDb;

interface ToolResult {
	content: Array<{ type: "text"; text: string }>;
}

function textResult(data: unknown): ToolResult {
	return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
}

function errorResult(message: string): ToolResult {
	return {
		content: [{ type: "text", text: JSON.stringify({ error: message }) }],
	};
}

export const itemToolDefinitions = [
	{
		name: "list_items",
		description:
			"List all items in the gear collection, optionally filtered by category.",
		inputSchema: {
			categoryId: z.number().optional().describe("Filter items by category ID"),
		},
	},
	{
		name: "get_item",
		description: "Get a single item by its ID, including all details.",
		inputSchema: {
			id: z.number().describe("The item ID"),
		},
	},
	{
		name: "create_item",
		description:
			"Add a new item to the gear collection. Use this for items you've already decided on. For items you're still researching, use create_thread instead.",
		inputSchema: {
			name: z.string().describe("Item name"),
			categoryId: z.number().describe("Category ID"),
			weightGrams: z.number().optional().describe("Weight in grams"),
			priceCents: z.number().optional().describe("Price in cents"),
			notes: z.string().optional().describe("Notes about the item"),
			productUrl: z.string().optional().describe("URL to the product page"),
			imageFilename: z
				.string()
				.optional()
				.describe("Filename of an uploaded image"),
			imageSourceUrl: z
				.string()
				.optional()
				.describe("Original URL the image was fetched from"),
		},
	},
	{
		name: "update_item",
		description: "Update an existing item's fields.",
		inputSchema: {
			id: z.number().describe("The item ID to update"),
			name: z.string().optional().describe("Item name"),
			categoryId: z.number().optional().describe("Category ID"),
			weightGrams: z.number().optional().describe("Weight in grams"),
			priceCents: z.number().optional().describe("Price in cents"),
			notes: z.string().optional().describe("Notes about the item"),
			productUrl: z.string().optional().describe("URL to the product page"),
			imageFilename: z
				.string()
				.optional()
				.describe("Filename of an uploaded image"),
			imageSourceUrl: z
				.string()
				.optional()
				.describe("Original URL the image was fetched from"),
		},
	},
	{
		name: "delete_item",
		description: "Delete an item from the gear collection by ID.",
		inputSchema: {
			id: z.number().describe("The item ID to delete"),
		},
	},
];

export function registerItemTools(db: Db, userId: number) {
	return {
		list_items: async (args: { categoryId?: number }): Promise<ToolResult> => {
			try {
				let items = await getAllItems(db, userId);
				if (args.categoryId) {
					items = items.filter((i) => i.categoryId === args.categoryId);
				}
				return textResult(await withImageUrls(items));
			} catch (err) {
				return errorResult((err as Error).message);
			}
		},

		get_item: async (args: { id: number }): Promise<ToolResult> => {
			try {
				const item = await getItemById(db, userId, args.id);
				if (!item) return errorResult(`Item ${args.id} not found`);
				return textResult(await withImageUrl(item));
			} catch (err) {
				return errorResult((err as Error).message);
			}
		},

		create_item: async (args: {
			name: string;
			categoryId: number;
			weightGrams?: number;
			priceCents?: number;
			notes?: string;
			productUrl?: string;
			imageFilename?: string;
			imageSourceUrl?: string;
		}): Promise<ToolResult> => {
			try {
				const item = await createItem(db, userId, args);
				return textResult(item);
			} catch (err) {
				return errorResult((err as Error).message);
			}
		},

		update_item: async (args: {
			id: number;
			name?: string;
			categoryId?: number;
			weightGrams?: number;
			priceCents?: number;
			notes?: string;
			productUrl?: string;
			imageFilename?: string;
			imageSourceUrl?: string;
		}): Promise<ToolResult> => {
			try {
				const { id, ...data } = args;
				const item = await updateItem(db, userId, id, data);
				if (!item) return errorResult(`Item ${id} not found`);
				return textResult(item);
			} catch (err) {
				return errorResult((err as Error).message);
			}
		},

		delete_item: async (args: { id: number }): Promise<ToolResult> => {
			try {
				const item = await deleteItem(db, userId, args.id);
				if (!item) return errorResult(`Item ${args.id} not found`);
				return textResult({ deleted: true, item });
			} catch (err) {
				return errorResult((err as Error).message);
			}
		},
	};
}
