import type { AgentTool } from "@jaeswift/jae-agent-core";
import type { ToolResultMessage } from "@jaeswift/jae-ai";
import { Type } from "@sinclair/typebox";
import { html } from "lit";
import { GitCompare } from "lucide";
import { registerToolRenderer, renderHeader } from "./renderer-registry.js";
import type { ToolRenderer, ToolRenderResult } from "./types.js";

export interface DiffDetails {
	original: string;
	modified: string;
	filename?: string;
}

interface DiffParams {
	original: string;
	modified: string;
	filename?: string;
}

const diffSchema = Type.Object({
	original: Type.String({ description: "Original file content" }),
	modified: Type.String({ description: "Modified file content" }),
	filename: Type.Optional(Type.String({ description: "Filename for display" })),
});

function computeLineDiff(original: string, modified: string): Array<{ type: "add" | "remove" | "same"; line: string }> {
	const oldLines = original.split("\n");
	const newLines = modified.split("\n");
	const result: Array<{ type: "add" | "remove" | "same"; line: string }> = [];
	const maxLen = Math.max(oldLines.length, newLines.length);
	for (let i = 0; i < maxLen; i++) {
		if (i >= oldLines.length) {
			result.push({ type: "add", line: newLines[i] });
		} else if (i >= newLines.length) {
			result.push({ type: "remove", line: oldLines[i] });
		} else if (oldLines[i] === newLines[i]) {
			result.push({ type: "same", line: oldLines[i] });
		} else {
			result.push({ type: "remove", line: oldLines[i] });
			result.push({ type: "add", line: newLines[i] });
		}
	}
	return result;
}

export const diffTool: AgentTool<typeof diffSchema, DiffDetails> = {
	name: "show_diff",
	label: "Show Diff",
	description: "Show a diff between two versions of code or text",
	parameters: diffSchema,
	async execute(toolCallId, params, signal) {
		return {
			content: [{ type: "text", text: `Diff shown for: ${params.filename || "file"}` }],
			details: { original: params.original, modified: params.modified, filename: params.filename },
		};
	},
};

class DiffRenderer implements ToolRenderer<DiffParams, DiffDetails> {
	render(params: DiffParams | undefined, result: ToolResultMessage<DiffDetails> | undefined): ToolRenderResult {
		const state = result ? (result.isError ? "error" : "complete") : "inprogress";
		if (!result?.details) {
			return { content: renderHeader(state, GitCompare, `Diff: ${params?.filename || "file"}`), isCustom: false };
		}
		const { original, modified, filename } = result.details;
		const diffLines = computeLineDiff(original, modified);
		const adds = diffLines.filter((l) => l.type === "add").length;
		const removes = diffLines.filter((l) => l.type === "remove").length;

		return {
			content: html`
        <div class="flex flex-col gap-3">
          ${renderHeader(state, GitCompare, html`Diff: ${filename || "file"} <span class="text-green-500 ml-2">+${adds}</span><span class="text-red-500 ml-1">-${removes}</span>`)}
          <div class="rounded border border-border overflow-auto max-h-96 text-xs font-mono">
            ${diffLines.map(
					(l, i) => html`
              <div class="flex gap-0 ${
						l.type === "add"
							? "bg-green-500/10 text-green-700 dark:text-green-400"
							: l.type === "remove"
								? "bg-red-500/10 text-red-700 dark:text-red-400"
								: "text-muted-foreground"
					}">
                <span class="w-6 text-center shrink-0 select-none border-r border-border px-1">${i + 1}</span>
                <span class="px-2 whitespace-pre">${
							l.type === "add" ? "+ " : l.type === "remove" ? "- " : "  "
						}${l.line}</span>
              </div>
            `,
				)}
          </div>
        </div>
      `,
			isCustom: false,
		};
	}
}

registerToolRenderer("show_diff", new DiffRenderer());

export function createDiffTool(): AgentTool<typeof diffSchema, DiffDetails> {
	return diffTool;
}
