import {
  consumerConfigSchema,
  ConsumerConfig,
  createPermissionConsumerRequestSchema,
  Permissions,
  singleToolGroupSchema,
  ToolExtension,
  toolExtensionSchema,
  ToolExtensions,
  ToolGroup,
  toolGroupUpdateSchema,
} from "@mcpx/shared-model";
import { loggableError } from "@mcpx/toolkit-core/logging";
import express, { Router } from "express";
import { Logger } from "winston";
import z from "zod/v4";
import { env } from "../env.js";
import { AlreadyExistsError, NotFoundError } from "../errors.js";
import { Services } from "../services/services.js";

export function buildControlPlaneAppConfigRouter(
  authGuard: express.RequestHandler,
  services: Services,
  logger: Logger,
): Router {
  const router = Router();

  if (!env.ENABLE_CONTROL_PLANE_REST) {
    logger.debug(
      "Control Plane REST API is disabled. Skipping control plane routes.",
    );
    return router;
  }

  // ==================== TOOL GROUPS ====================

  router.get("/tool-groups", authGuard, async (_req, res) => {
    const toolGroups = services.controlPlane.config.getToolGroups();
    res.status(200).json(toolGroups satisfies ToolGroup[]);
  });

  router.get("/tool-groups/:name", authGuard, async (req, res) => {
    const name = req.params["name"];
    if (!name) {
      res.status(400).json({ message: "Tool group name is required" });
      return;
    }

    const toolGroup = services.controlPlane.config.getToolGroup({ name });
    if (!toolGroup) {
      res.status(404).json({ message: `Tool group '${name}' not found` });
      return;
    }

    res.status(200).json(toolGroup satisfies ToolGroup);
  });

  router.post("/tool-groups", authGuard, async (req, res) => {
    const parsed = singleToolGroupSchema.safeParse(req.body);
    if (!parsed.success) {
      res.status(400).json({
        message: "Invalid request schema",
        error: z.treeifyError(parsed.error),
      });
      return;
    }

    try {
      const toolGroup = await services.controlPlane.config.addToolGroup({
        group: parsed.data,
      });
      res.status(201).json(toolGroup satisfies ToolGroup);
    } catch (e) {
      if (e instanceof AlreadyExistsError) {
        res.status(409).json({ message: e.message, error: loggableError(e) });
        return;
      }
      logger.error("Error adding tool group", { error: loggableError(e) });
      res.status(500).json({ message: "Internal server error" });
    }
  });

  router.put("/tool-groups/:name", authGuard, async (req, res) => {
    const name = req.params["name"];
    if (!name) {
      res.status(400).json({ message: "Tool group name is required" });
      return;
    }

    const parsed = toolGroupUpdateSchema.safeParse(req.body);
    if (!parsed.success) {
      res.status(400).json({
        message: "Invalid request schema",
        error: z.treeifyError(parsed.error),
      });
      return;
    }

    try {
      const toolGroup = await services.controlPlane.config.updateToolGroup({
        name,
        updates: parsed.data,
      });
      res.status(200).json(toolGroup satisfies ToolGroup);
    } catch (e) {
      if (e instanceof NotFoundError) {
        res.status(404).json({ message: e.message, error: loggableError(e) });
        return;
      }
      if (e instanceof AlreadyExistsError) {
        res.status(409).json({ message: e.message, error: loggableError(e) });
        return;
      }
      logger.error("Error updating tool group", { error: loggableError(e) });
      res.status(500).json({ message: "Internal server error" });
    }
  });

  router.delete("/tool-groups/:name", authGuard, async (req, res) => {
    const name = req.params["name"];
    if (!name) {
      res.status(400).json({ message: "Tool group name is required" });
      return;
    }

    try {
      await services.controlPlane.config.deleteToolGroup({ name });
      res.status(200).json({ message: `Tool group '${name}' deleted` });
    } catch (e) {
      if (e instanceof NotFoundError) {
        res.status(404).json({ message: e.message, error: loggableError(e) });
        return;
      }
      logger.error("Error deleting tool group", { error: loggableError(e) });
      res.status(500).json({ message: "Internal server error" });
    }
  });

  // ==================== TOOL EXTENSIONS ====================

  const toolExtensionUpdateSchema = toolExtensionSchema.omit({ name: true });

  router.get("/tool-extensions", authGuard, async (_req, res) => {
    const extensions = services.controlPlane.config.getToolExtensions();
    res.status(200).json(extensions satisfies ToolExtensions);
  });

  router.get(
    "/tool-extensions/:serverName/:originalToolName/:customToolName",
    authGuard,
    async (req, res) => {
      const { serverName, originalToolName, customToolName } = req.params;
      if (!serverName || !originalToolName || !customToolName) {
        res.status(400).json({ message: "All path parameters are required" });
        return;
      }

      const extension = services.controlPlane.config.getToolExtension({
        serverName,
        originalToolName,
        customToolName,
      });
      if (!extension) {
        res.status(404).json({
          message: `Tool extension '${customToolName}' not found for ${serverName}/${originalToolName}`,
        });
        return;
      }

      res.status(200).json(extension satisfies ToolExtension);
    },
  );

  router.post(
    "/tool-extensions/:serverName/:originalToolName",
    authGuard,
    async (req, res) => {
      const { serverName, originalToolName } = req.params;
      if (!serverName || !originalToolName) {
        res.status(400).json({ message: "All path parameters are required" });
        return;
      }

      const parsed = toolExtensionSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({
          message: "Invalid request schema",
          error: z.treeifyError(parsed.error),
        });
        return;
      }

      try {
        const extension = await services.controlPlane.config.addToolExtension({
          serverName,
          originalToolName,
          extension: parsed.data,
        });
        res.status(201).json(extension satisfies ToolExtension);
      } catch (e) {
        if (e instanceof AlreadyExistsError) {
          res.status(409).json({ message: e.message, error: loggableError(e) });
          return;
        }
        logger.error("Error adding tool extension", {
          error: loggableError(e),
        });
        res.status(500).json({ message: "Internal server error" });
      }
    },
  );

  router.put(
    "/tool-extensions/:serverName/:originalToolName/:customToolName",
    authGuard,
    async (req, res) => {
      const { serverName, originalToolName, customToolName } = req.params;
      if (!serverName || !originalToolName || !customToolName) {
        res.status(400).json({ message: "All path parameters are required" });
        return;
      }

      const parsed = toolExtensionUpdateSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({
          message: "Invalid request schema",
          error: z.treeifyError(parsed.error),
        });
        return;
      }

      try {
        const extension =
          await services.controlPlane.config.updateToolExtension({
            serverName,
            originalToolName,
            customToolName,
            updates: parsed.data,
          });
        res.status(200).json(extension satisfies ToolExtension);
      } catch (e) {
        if (e instanceof NotFoundError) {
          res.status(404).json({ message: e.message, error: loggableError(e) });
          return;
        }
        logger.error("Error updating tool extension", {
          error: loggableError(e),
        });
        res.status(500).json({ message: "Internal server error" });
      }
    },
  );

  router.delete(
    "/tool-extensions/:serverName/:originalToolName/:customToolName",
    authGuard,
    async (req, res) => {
      const { serverName, originalToolName, customToolName } = req.params;
      if (!serverName || !originalToolName || !customToolName) {
        res.status(400).json({ message: "All path parameters are required" });
        return;
      }

      try {
        await services.controlPlane.config.deleteToolExtension({
          serverName,
          originalToolName,
          customToolName,
        });
        res.status(200).json({
          message: `Tool extension '${customToolName}' deleted from ${serverName}/${originalToolName}`,
        });
      } catch (e) {
        if (e instanceof NotFoundError) {
          res.status(404).json({ message: e.message, error: loggableError(e) });
          return;
        }
        logger.error("Error deleting tool extension", {
          error: loggableError(e),
        });
        res.status(500).json({ message: "Internal server error" });
      }
    },
  );

  // ==================== PERMISSIONS ====================

  router.get("/permissions", authGuard, async (_req, res) => {
    const permissions = services.controlPlane.config.getPermissions();
    res.status(200).json(permissions satisfies Permissions);
  });

  router.get("/permissions/default", authGuard, async (_req, res) => {
    const defaultPermission =
      services.controlPlane.config.getDefaultPermission();
    res.status(200).json(defaultPermission satisfies ConsumerConfig);
  });

  router.get("/permissions/consumers", authGuard, async (_req, res) => {
    const consumers = services.controlPlane.config.getPermissionConsumers();
    res.status(200).json(consumers satisfies Record<string, ConsumerConfig>);
  });

  router.get(
    "/permissions/consumers/:consumerName",
    authGuard,
    async (req, res) => {
      const name = req.params["consumerName"];
      if (!name) {
        res.status(400).json({ message: "Consumer name is required" });
        return;
      }

      const consumer = services.controlPlane.config.getPermissionConsumer({
        name,
      });
      if (!consumer) {
        res
          .status(404)
          .json({ message: `Permission consumer '${name}' not found` });
        return;
      }

      res.status(200).json(consumer satisfies ConsumerConfig);
    },
  );

  router.post("/permissions/consumers", authGuard, async (req, res) => {
    const parsed = createPermissionConsumerRequestSchema.safeParse(req.body);
    if (!parsed.success) {
      res.status(400).json({
        message: "Invalid request schema",
        error: z.treeifyError(parsed.error),
      });
      return;
    }

    try {
      const consumer = await services.controlPlane.config.addPermissionConsumer(
        {
          name: parsed.data.name,
          config: parsed.data.config,
        },
      );
      res.status(201).json(consumer satisfies ConsumerConfig);
    } catch (e) {
      if (e instanceof AlreadyExistsError) {
        res.status(409).json({ message: e.message, error: loggableError(e) });
        return;
      }
      logger.error("Error adding permission consumer", {
        error: loggableError(e),
      });
      res.status(500).json({ message: "Internal server error" });
    }
  });

  router.put("/permissions/default", authGuard, async (req, res) => {
    const parsed = consumerConfigSchema.safeParse(req.body);
    if (!parsed.success) {
      res.status(400).json({
        message: "Invalid request schema",
        error: z.treeifyError(parsed.error),
      });
      return;
    }

    try {
      const defaultPermission =
        await services.controlPlane.config.updateDefaultPermission({
          config: parsed.data,
        });
      res.status(200).json(defaultPermission satisfies ConsumerConfig);
    } catch (e) {
      logger.error("Error updating default permission", {
        error: loggableError(e),
      });
      res.status(500).json({ message: "Internal server error" });
    }
  });

  router.put(
    "/permissions/consumers/:consumerName",
    authGuard,
    async (req, res) => {
      const name = req.params["consumerName"];
      if (!name) {
        res.status(400).json({ message: "Consumer name is required" });
        return;
      }

      const parsed = consumerConfigSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({
          message: "Invalid request schema",
          error: z.treeifyError(parsed.error),
        });
        return;
      }

      try {
        const consumer =
          await services.controlPlane.config.updatePermissionConsumer({
            name,
            config: parsed.data,
          });
        res.status(200).json(consumer satisfies ConsumerConfig);
      } catch (e) {
        if (e instanceof NotFoundError) {
          res.status(404).json({ message: e.message, error: loggableError(e) });
          return;
        }
        logger.error("Error updating permission consumer", {
          error: loggableError(e),
        });
        res.status(500).json({ message: "Internal server error" });
      }
    },
  );

  router.delete(
    "/permissions/consumers/:consumerName",
    authGuard,
    async (req, res) => {
      const name = req.params["consumerName"];
      if (!name) {
        res.status(400).json({ message: "Consumer name is required" });
        return;
      }

      try {
        await services.controlPlane.config.deletePermissionConsumer({ name });
        res
          .status(200)
          .json({ message: `Permission consumer '${name}' deleted` });
      } catch (e) {
        if (e instanceof NotFoundError) {
          res.status(404).json({ message: e.message, error: loggableError(e) });
          return;
        }
        logger.error("Error deleting permission consumer", {
          error: loggableError(e),
        });
        res.status(500).json({ message: "Internal server error" });
      }
    },
  );

  router.get("/permissions/clientNames", authGuard, async (_req, res) => {
    const clientNames = services.controlPlane.config.getPermissionClientNames();
    res.status(200).json(clientNames satisfies Record<string, ConsumerConfig>);
  });

  router.get(
    "/permissions/clientNames/:clientName",
    authGuard,
    async (req, res) => {
      const name = req.params["clientName"];
      if (!name) {
        res.status(400).json({ message: "Client name is required" });
        return;
      }

      const entry = services.controlPlane.config.getPermissionClientName({
        name,
      });
      if (!entry) {
        res
          .status(404)
          .json({ message: `Permission clientName '${name}' not found` });
        return;
      }

      res.status(200).json(entry satisfies ConsumerConfig);
    },
  );

  router.post("/permissions/clientNames", authGuard, async (req, res) => {
    const parsed = createPermissionConsumerRequestSchema.safeParse(req.body);
    if (!parsed.success) {
      res.status(400).json({
        message: "Invalid request schema",
        error: z.treeifyError(parsed.error),
      });
      return;
    }

    try {
      const entry = await services.controlPlane.config.addPermissionClientName({
        name: parsed.data.name,
        config: parsed.data.config,
      });
      res.status(201).json(entry satisfies ConsumerConfig);
    } catch (e) {
      if (e instanceof AlreadyExistsError) {
        res.status(409).json({ message: e.message, error: loggableError(e) });
        return;
      }
      logger.error("Error adding permission clientName", {
        error: loggableError(e),
      });
      res.status(500).json({ message: "Internal server error" });
    }
  });

  router.put(
    "/permissions/clientNames/:clientName",
    authGuard,
    async (req, res) => {
      const name = req.params["clientName"];
      if (!name) {
        res.status(400).json({ message: "Client name is required" });
        return;
      }

      const parsed = consumerConfigSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({
          message: "Invalid request schema",
          error: z.treeifyError(parsed.error),
        });
        return;
      }

      try {
        const entry =
          await services.controlPlane.config.updatePermissionClientName({
            name,
            config: parsed.data,
          });
        res.status(200).json(entry satisfies ConsumerConfig);
      } catch (e) {
        if (e instanceof NotFoundError) {
          res.status(404).json({ message: e.message, error: loggableError(e) });
          return;
        }
        logger.error("Error updating permission clientName", {
          error: loggableError(e),
        });
        res.status(500).json({ message: "Internal server error" });
      }
    },
  );

  router.delete(
    "/permissions/clientNames/:clientName",
    authGuard,
    async (req, res) => {
      const name = req.params["clientName"];
      if (!name) {
        res.status(400).json({ message: "Client name is required" });
        return;
      }

      try {
        await services.controlPlane.config.deletePermissionClientName({ name });
        res
          .status(200)
          .json({ message: `Permission clientName '${name}' deleted` });
      } catch (e) {
        if (e instanceof NotFoundError) {
          res.status(404).json({ message: e.message, error: loggableError(e) });
          return;
        }
        logger.error("Error deleting permission clientName", {
          error: loggableError(e),
        });
        res.status(500).json({ message: "Internal server error" });
      }
    },
  );

  // ==================== SERVER ATTRIBUTES ====================

  router.put("/target-server/:name/activate", authGuard, async (req, res) => {
    const name = req.params["name"];
    if (!name) {
      res.status(400).json({ message: "Target server name is required" });
      return;
    }
    try {
      await services.controlPlane.config.activateTargetServer(name);
      logger.info("Activated target server", { name });
      res.status(200).json({ message: "Target server activated successfully" });
    } catch (e) {
      const error = loggableError(e);
      logger.error("Error activating target server", { error, name });
      res.status(500).json(error);
    }
  });

  router.put("/target-server/:name/deactivate", authGuard, async (req, res) => {
    const name = req.params["name"];
    if (!name) {
      res.status(400).json({ message: "Target server name is required" });
      return;
    }
    try {
      await services.controlPlane.config.deactivateTargetServer(name);
      logger.info("Deactivated target server", { name });
      res
        .status(200)
        .json({ message: "Target server deactivated successfully" });
    } catch (e) {
      const error = loggableError(e);
      logger.error("Error deactivating target server", { error, name });
      res.status(500).json(error);
    }
  });

  router.get("/target-servers/attributes", authGuard, async (_req, res) => {
    try {
      const targetServerAttributes =
        services.controlPlane.config.getTargetServerAttributes();
      res.status(200).json({ targetServerAttributes });
    } catch (e) {
      const error = loggableError(e);
      logger.error("Error fetching target server attributes", { error });
      res.status(500).json(error);
    }
  });

  return router;
}
