import type { ControllerResponse } from "../../shared/types/common.types.js";
import { ErrorType, McpError } from "../../shared/utils/error.util.js";
import { handleControllerError } from "../../shared/utils/error-handler.util.js";
import { Logger } from "../../shared/utils/logger.util.js";
import {
{{#if:list}}
	format{{domainNamePascal}}List,
{{/if:list}}
{{#if:get}}
	format{{domainNamePascal}}Details,
{{/if:get}}
{{#if:create}}
	formatAdd{{domainNamePascal}}Result,
{{/if:create}}
{{#if:update}}
	formatUpdate{{domainNamePascal}}Result,
{{/if:update}}
{{#if:delete}}
	formatRemove{{domainNamePascal}}Result,
{{/if:delete}}
} from "./{{domainName}}.formatter.js";
import { {{domainName}}Service } from "./{{domainName}}.service.js";
import type {
{{#if:list}}
	List{{domainNamePascal}}ToolArgsType,
{{/if:list}}
{{#if:get}}
	Get{{domainNamePascal}}ToolArgsType,
{{/if:get}}
{{#if:create}}
	Add{{domainNamePascal}}ToolArgsType,
{{/if:create}}
{{#if:update}}
	Update{{domainNamePascal}}ToolArgsType,
{{/if:update}}
{{#if:delete}}
	Remove{{domainNamePascal}}ToolArgsType,
{{/if:delete}}
} from "./{{domainName}}.types.js";

/**
 * @namespace {{domainNamePascal}}Controller
 * @description Controller responsible for handling Lokalise {{domainNamePascal}} API operations.
 *              It orchestrates calls to the {{domainName}} service, applies defaults,
 *              maps options, and formats the response using the formatter.
 */

{{#if:list}}
/**
 * @function list{{domainNamePascal}}
 * @description Fetches a list of {{domainName}} from a Lokalise project.
 * @memberof {{domainNamePascal}}Controller
 * @param {List{{domainNamePascal}}ToolArgsType} args - Arguments containing project ID and pagination options
 * @returns {Promise<ControllerResponse>} A promise that resolves to the standard controller response containing the formatted {{domainName}} list in Markdown.
 * @throws {McpError} Throws an McpError (handled by `handleControllerError`) if the service call fails or returns an error.
 */
async function list{{domainNamePascal}}(
	args: List{{domainNamePascal}}ToolArgsType,
): Promise<ControllerResponse> {
	const methodLogger = Logger.forContext(
		"{{domainName}}.controller.ts",
		"list{{domainNamePascal}}",
	);
	methodLogger.debug("Getting Lokalise {{domainName}} list...", args);

	try {
		// Validate project ID
		if (!args.projectId || typeof args.projectId !== "string") {
			throw new McpError(
				"Project ID is required and must be a string.",
				ErrorType.API_ERROR,
			);
		}

		// Validate pagination parameters
		if (args.limit !== undefined && (args.limit < 1 || args.limit > 100)) {
			throw new McpError(
				"Invalid limit parameter. Must be between 1 and 100.",
				ErrorType.API_ERROR,
			);
		}

		if (args.page !== undefined && args.page < 1) {
			throw new McpError(
				"Invalid page parameter. Must be 1 or greater.",
				ErrorType.API_ERROR,
			);
		}

		// Call service layer
		const result = await {{domainName}}Service.list(args);

		// Format response using the formatter
		const formattedContent = format{{domainNamePascal}}List(result, args.projectId);

		methodLogger.debug("{{domainNamePascal}}s list fetched successfully", {
			projectId: args.projectId,
			{{domainName}}Count: result.items?.length || 0,
		});

		return {
			content: formattedContent,
		};
	} catch (error: unknown) {
		throw handleControllerError(error, {
			source: "{{domainNamePascal}}Controller.list{{domainNamePascal}}s",
			entityType: "{{domainNamePascal}}s",
			entityId: args.projectId,
			operation: "listing",
		});
	}
}
{{/if:list}}

{{#if:get}}
/**
 * @function get{{domainNamePascal}}
 * @description Fetches details of a specific {{domainName}}.
 * @memberof {{domainNamePascal}}Controller
 * @param {Get{{domainNamePascal}}ToolArgsType} args - Arguments containing project ID and {{domainName}} ID
 * @returns {Promise<ControllerResponse>} A promise that resolves to the formatted {{domainName}} details.
 * @throws {McpError} Throws an McpError if the service call fails.
 */
async function get{{domainNamePascal}}(
	args: Get{{domainNamePascal}}ToolArgsType,
): Promise<ControllerResponse> {
	const methodLogger = Logger.forContext(
		"{{domainName}}.controller.ts",
		"get{{domainNamePascal}}",
	);
	methodLogger.debug("Getting {{domainName}} details...", args);

	try {
		// Validate inputs
		if (!args.projectId || typeof args.projectId !== "string") {
			throw new McpError(
				"Project ID is required and must be a string.",
				ErrorType.API_ERROR,
			);
		}

		if (!args.{{domainName}}Id) {
			throw new McpError("{{domainNamePascal}} ID is required.", ErrorType.API_ERROR);
		}

		// Call service layer
		const result = await {{domainName}}Service.get(args);

		// Format response
		const formattedContent = format{{domainNamePascal}}Details(result);

		methodLogger.debug("{{domainNamePascal}} details fetched successfully", {
			projectId: args.projectId,
			{{domainName}}Id: args.{{domainName}}Id,
		});

		return {
			content: formattedContent,
		};
	} catch (error: unknown) {
		throw handleControllerError(error, {
			source: "{{domainNamePascal}}Controller.get{{domainNamePascal}}",
			entityType: "{{domainNamePascal}}",
			entityId: { project: args.projectId, {{domainName}}: String(args.{{domainName}}Id) },
			operation: "retrieving",
		});
	}
}
{{/if:get}}

{{#if:create}}
/**
 * @function add{{domainNamePascal}}
 * @description Adds one or more {{domainName}} to a project.
 * @memberof {{domainNamePascal}}Controller
 * @param {Add{{domainNamePascal}}ToolArgsType} args - Arguments containing project ID and {{domainName}} data
 * @returns {Promise<ControllerResponse>} A promise that resolves to the formatted result.
 * @throws {McpError} Throws an McpError if the service call fails.
 */
async function add{{domainNamePascal}}(
	args: Add{{domainNamePascal}}ToolArgsType,
): Promise<ControllerResponse> {
	const methodLogger = Logger.forContext(
		"{{domainName}}.controller.ts",
		"add{{domainNamePascal}}",
	);
	methodLogger.debug("Adding {{domainName}}...", args);

	try {
		// Validate inputs
		if (!args.projectId || typeof args.projectId !== "string") {
			throw new McpError(
				"Project ID is required and must be a string.",
				ErrorType.API_ERROR,
			);
		}

		if (!args.{{domainName}} || args.{{domainName}}.length === 0) {
			throw new McpError(
				"At least one {{domainName}} is required.",
				ErrorType.API_ERROR,
			);
		}

		// Call service layer
		const result = await {{domainName}}Service.create(args);

		// Format response
		const formattedContent = formatAdd{{domainNamePascal}}sResult(result);

		methodLogger.debug("{{domainNamePascal}}s added successfully", {
			projectId: args.projectId,
			addedCount: result.length,
		});

		return {
			content: formattedContent,
		};
	} catch (error: unknown) {
		throw handleControllerError(error, {
			source: "{{domainNamePascal}}Controller.add{{domainNamePascal}}s",
			entityType: "{{domainNamePascal}}s",
			entityId: args.projectId,
			operation: "adding",
		});
	}
}
{{/if:create}}

{{#if:update}}
/**
 * @function update{{domainNamePascal}}
 * @description Updates a {{domainName}} in a project.
 * @memberof {{domainNamePascal}}Controller
 * @param {Update{{domainNamePascal}}ToolArgsType} args - Arguments containing project ID, {{domainName}} ID and update data
 * @returns {Promise<ControllerResponse>} A promise that resolves to the formatted update result.
 * @throws {McpError} Throws an McpError if the service call fails.
 */
async function update{{domainNamePascal}}(
	args: Update{{domainNamePascal}}ToolArgsType,
): Promise<ControllerResponse> {
	const methodLogger = Logger.forContext(
		"{{domainName}}.controller.ts",
		"update{{domainNamePascal}}",
	);
	methodLogger.debug("Updating {{domainName}}...", args);

	try {
		// Validate inputs
		if (!args.projectId || typeof args.projectId !== "string") {
			throw new McpError(
				"Project ID is required and must be a string.",
				ErrorType.API_ERROR,
			);
		}

		if (!args.{{domainName}}Id) {
			throw new McpError("{{domainNamePascal}} ID is required.", ErrorType.API_ERROR);
		}

		// Call service layer
		const result = await {{domainName}}Service.update(args);

		// Format response
		const formattedContent = formatUpdate{{domainNamePascal}}Result(result);

		methodLogger.debug("{{domainNamePascal}} updated successfully", {
			projectId: args.projectId,
			{{domainName}}Id: args.{{domainName}}Id,
		});

		return {
			content: formattedContent,
		};
	} catch (error: unknown) {
		throw handleControllerError(error, {
			source: "{{domainNamePascal}}Controller.update{{domainNamePascal}}",
			entityType: "{{domainNamePascal}}",
			entityId: { project: args.projectId, {{domainName}}: String(args.{{domainName}}Id) },
			operation: "updating",
		});
	}
}
{{/if:update}}

{{#if:delete}}
/**
 * @function remove{{domainNamePascal}}
 * @description Removes a {{domainName}} from a project.
 * @memberof {{domainNamePascal}}Controller
 * @param {Remove{{domainNamePascal}}ToolArgsType} args - Arguments containing project ID and {{domainName}} ID
 * @returns {Promise<ControllerResponse>} A promise that resolves to the formatted deletion result.
 * @throws {McpError} Throws an McpError if the service call fails.
 */
async function remove{{domainNamePascal}}(
	args: Remove{{domainNamePascal}}ToolArgsType,
): Promise<ControllerResponse> {
	const methodLogger = Logger.forContext(
		"{{domainName}}.controller.ts",
		"remove{{domainNamePascal}}",
	);
	methodLogger.debug("Removing {{domainName}}...", args);

	try {
		// Validate inputs
		if (!args.projectId || typeof args.projectId !== "string") {
			throw new McpError(
				"Project ID is required and must be a string.",
				ErrorType.API_ERROR,
			);
		}

		if (!args.{{domainName}}Id) {
			throw new McpError("{{domainNamePascal}} ID is required.", ErrorType.API_ERROR);
		}

		// Call service layer
		const result = await {{domainName}}Service.delete(args);

		// Format response
		const formattedContent = formatRemove{{domainNamePascal}}Result(result);

		methodLogger.debug("{{domainNamePascal}} removed successfully", {
			projectId: args.projectId,
			{{domainName}}Id: args.{{domainName}}Id,
		});

		return {
			content: formattedContent,
		};
	} catch (error: unknown) {
		throw handleControllerError(error, {
			source: "{{domainNamePascal}}Controller.remove{{domainNamePascal}}",
			entityType: "{{domainNamePascal}}",
			entityId: { project: args.projectId, {{domainName}}: String(args.{{domainName}}Id) },
			operation: "removing",
		});
	}
}
{{/if:delete}}

/**
 * Export the controller functions
 */
const {{domainName}}Controller = {
{{#if:list}}
	list{{domainNamePascal}},
{{/if:list}}
{{#if:get}}
	get{{domainNamePascal}},
{{/if:get}}
{{#if:create}}
	add{{domainNamePascal}},
{{/if:create}}
{{#if:update}}
	update{{domainNamePascal}},
{{/if:update}}
{{#if:delete}}
	remove{{domainNamePascal}},
{{/if:delete}}
};

export default {{domainName}}Controller;