import { NextResponse } from "next/server";
import { generateEntityAPI } from "./api-generator.js";
import { getEntityConfig } from "./registry.js";
import { rateLimit } from "../rate-limit.js";
import { validateAPIKey } from "../auth/api-keys.js";
function generateExternalAPI(entityName, options = {}) {
  const entityConfig = getEntityConfig(entityName);
  if (!entityConfig) {
    throw new Error(`Entity configuration not found: ${entityName}`);
  }
  if (!entityConfig.access.api) {
    throw new Error(`Entity ${entityName} does not have external API enabled`);
  }
  const {
    enableAPIKeyAuth = true,
    enableRateLimit: enableRL = true,
    enableCORS = true,
    rateLimitConfig = {
      windowMs: 60 * 1e3,
      // 1 minute
      maxRequests: 60
      // Default rate limit
    },
    corsOptions = {
      origins: ["*"],
      methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
      headers: ["Content-Type", "Authorization", "X-API-Key"]
    }
  } = options;
  const baseAPI = generateEntityAPI(entityName, {
    ...options,
    enableAuth: false
    // We'll handle API key auth separately
  });
  return {
    GET: wrapExternalHandler(baseAPI.GET, entityConfig, {
      enableAPIKeyAuth,
      enableRateLimit: enableRL,
      enableCORS,
      rateLimitConfig,
      corsOptions,
      action: "read"
    }),
    POST: wrapExternalHandler(baseAPI.POST, entityConfig, {
      enableAPIKeyAuth,
      enableRateLimit: enableRL,
      enableCORS,
      rateLimitConfig,
      corsOptions,
      action: "create"
    }),
    PATCH: wrapExternalHandler(baseAPI.PATCH, entityConfig, {
      enableAPIKeyAuth,
      enableRateLimit: enableRL,
      enableCORS,
      rateLimitConfig,
      corsOptions,
      action: "update"
    }),
    DELETE: wrapExternalHandler(baseAPI.DELETE, entityConfig, {
      enableAPIKeyAuth,
      enableRateLimit: enableRL,
      enableCORS,
      rateLimitConfig,
      corsOptions,
      action: "delete"
    }),
    OPTIONS: createOPTIONSHandler(corsOptions)
  };
}
function wrapExternalHandler(baseHandler, entityConfig, options) {
  return async (request, context) => {
    var _a;
    try {
      if (options.enableCORS && request.method === "OPTIONS") {
        return createOPTIONSHandler(options.corsOptions)(request);
      }
      const allowedMethods = ["GET", "POST", "PATCH", "DELETE"];
      if (!allowedMethods.includes(request.method)) {
        return createErrorResponse(405, "Method not allowed", {
          allowedMethods
        });
      }
      if (options.enableRateLimit && true) {
        const rateLimitResult = await rateLimit({
          key: getClientIdentifier(request),
          windowMs: options.rateLimitConfig.windowMs,
          maxRequests: options.rateLimitConfig.maxRequests
        });
        if (!rateLimitResult.success) {
          return createErrorResponse(429, "Rate limit exceeded", {
            limit: options.rateLimitConfig.maxRequests,
            windowMs: options.rateLimitConfig.windowMs,
            retryAfter: rateLimitResult.retryAfter
          });
        }
      }
      if (options.enableAPIKeyAuth) {
        const apiKey = request.headers.get("X-API-Key") || ((_a = request.headers.get("Authorization")) == null ? void 0 : _a.replace("Bearer ", ""));
        if (!apiKey) {
          return createErrorResponse(401, "API key required", {
            hint: "Include X-API-Key header or Authorization: Bearer <api-key>"
          });
        }
        const keyValidation = await validateAPIKey(apiKey, {
          requiredScopes: [`${entityConfig.slug}:${options.action}`],
          entityName: entityConfig.slug
        });
        if (!keyValidation.valid) {
          return createErrorResponse(401, "Invalid API key", {
            reason: keyValidation.reason
          });
        }
        request.headers.set("x-client-id", keyValidation.clientId || "");
        request.headers.set("x-api-key-id", keyValidation.apiKeyId || "");
        if (keyValidation.userId) {
          request.headers.set("x-user-id", keyValidation.userId);
        }
      }
      const response = await baseHandler(request, context);
      if (options.enableCORS) {
        addCORSHeaders(response, options.corsOptions);
      }
      response.headers.set("X-API-Version", "v1");
      response.headers.set("X-Entity-Type", entityConfig.slug);
      response.headers.set("X-Response-Time", Date.now().toString());
      if (options.enableRateLimit) {
        response.headers.set("X-RateLimit-Limit", options.rateLimitConfig.maxRequests.toString());
        response.headers.set("X-RateLimit-Window", options.rateLimitConfig.windowMs.toString());
      }
      return response;
    } catch (error) {
      console.error(`External API error for ${entityConfig.slug}:`, error);
      return createErrorResponse(500, "Internal server error", {
        timestamp: (/* @__PURE__ */ new Date()).toISOString(),
        entity: entityConfig.slug
      });
    }
  };
}
function createOPTIONSHandler(corsOptions) {
  return async (request) => {
    const response = new NextResponse(null, { status: 204 });
    addCORSHeaders(response, corsOptions, request);
    return response;
  };
}
function addCORSHeaders(response, corsOptions, request) {
  const origin = request == null ? void 0 : request.headers.get("origin");
  if (corsOptions.origins.includes("*") || origin && corsOptions.origins.includes(origin)) {
    response.headers.set("Access-Control-Allow-Origin", origin || "*");
  }
  response.headers.set("Access-Control-Allow-Methods", corsOptions.methods.join(", "));
  response.headers.set("Access-Control-Allow-Headers", corsOptions.headers.join(", "));
  response.headers.set("Access-Control-Max-Age", "86400");
  response.headers.set("Access-Control-Allow-Credentials", "true");
}
function createErrorResponse(status, message, details) {
  return NextResponse.json({
    error: {
      status,
      message,
      timestamp: (/* @__PURE__ */ new Date()).toISOString(),
      ...details
    }
  }, { status });
}
function getClientIdentifier(request) {
  const apiKeyId = request.headers.get("x-api-key-id");
  const clientId = request.headers.get("x-client-id");
  const ip = request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "unknown";
  return apiKeyId || clientId || ip;
}
function generateOpenAPISpec(entityName) {
  const entityConfig = getEntityConfig(entityName);
  if (!entityConfig) {
    throw new Error(`Entity configuration not found: ${entityName}`);
  }
  const paths = {};
  const basePath = `/api/v1/${entityName}`;
  const entitySchema = {
    type: "object",
    properties: entityConfig.fields.reduce((props, field) => {
      props[field.name] = {
        type: getOpenAPIType(field.type),
        description: field.display.description || field.display.label,
        ...field.required ? {} : { nullable: true }
      };
      return props;
    }, {}),
    required: entityConfig.fields.filter((f) => f.required).map((f) => f.name)
  };
  paths[basePath] = {
    get: {
      summary: `List ${entityConfig.names.plural}`,
      parameters: [
        { name: "page", in: "query", schema: { type: "integer", default: 1 } },
        { name: "limit", in: "query", schema: { type: "integer", default: 10, maximum: 100 } },
        { name: "search", in: "query", schema: { type: "string" } },
        { name: "sortBy", in: "query", schema: { type: "string" } },
        { name: "sortOrder", in: "query", schema: { type: "string", enum: ["asc", "desc"] } },
        ...entityConfig.childEntities ? [
          { name: "children", in: "query", schema: { type: "string", description: "Comma-separated child entity names to include" } }
        ] : []
      ],
      responses: {
        200: {
          description: `List of ${entityConfig.names.plural}`,
          content: {
            "application/json": {
              schema: {
                type: "object",
                properties: {
                  data: { type: "array", items: { $ref: `#/components/schemas/${entityConfig.slug}` } },
                  meta: {
                    type: "object",
                    properties: {
                      total: { type: "integer" },
                      page: { type: "integer" },
                      limit: { type: "integer" },
                      hasMore: { type: "boolean" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    post: {
      summary: `Create ${entityConfig.names.singular}`,
      requestBody: {
        content: {
          "application/json": {
            schema: { $ref: `#/components/schemas/${entityConfig.slug}Create` }
          }
        }
      },
      responses: {
        201: {
          description: `Created ${entityConfig.names.singular}`,
          content: {
            "application/json": {
              schema: {
                type: "object",
                properties: {
                  data: { $ref: `#/components/schemas/${entityConfig.slug}` }
                }
              }
            }
          }
        }
      }
    }
  };
  paths[`${basePath}/{id}`] = {
    get: {
      summary: `Get ${entityConfig.names.singular}`,
      parameters: [
        { name: "id", in: "path", required: true, schema: { type: "string" } },
        ...entityConfig.childEntities ? [
          { name: "children", in: "query", schema: { type: "string" } }
        ] : []
      ],
      responses: {
        200: {
          description: entityConfig.names.singular,
          content: {
            "application/json": {
              schema: {
                type: "object",
                properties: {
                  data: { $ref: `#/components/schemas/${entityConfig.slug}` }
                }
              }
            }
          }
        }
      }
    },
    patch: {
      summary: `Update ${entityConfig.names.singular}`,
      parameters: [
        { name: "id", in: "path", required: true, schema: { type: "string" } }
      ],
      requestBody: {
        content: {
          "application/json": {
            schema: { $ref: `#/components/schemas/${entityConfig.slug}Update` }
          }
        }
      },
      responses: {
        200: {
          description: `Updated ${entityConfig.names.singular}`,
          content: {
            "application/json": {
              schema: {
                type: "object",
                properties: {
                  data: { $ref: `#/components/schemas/${entityConfig.slug}` }
                }
              }
            }
          }
        }
      }
    },
    delete: {
      summary: `Delete ${entityConfig.names.singular}`,
      parameters: [
        { name: "id", in: "path", required: true, schema: { type: "string" } }
      ],
      responses: {
        200: {
          description: "Deleted successfully",
          content: {
            "application/json": {
              schema: {
                type: "object",
                properties: {
                  success: { type: "boolean" }
                }
              }
            }
          }
        }
      }
    }
  };
  return {
    openapi: "3.0.0",
    info: {
      title: `${entityConfig.names.singular} API`,
      version: "1.0.0",
      description: `REST API for ${entityConfig.names.plural}`
    },
    paths,
    components: {
      schemas: {
        [entityConfig.slug]: entitySchema,
        [`${entityConfig.slug}Create`]: {
          ...entitySchema,
          required: entityConfig.fields.filter((f) => f.required && !f.api.readOnly).map((f) => f.name)
        },
        [`${entityConfig.slug}Update`]: {
          ...entitySchema,
          required: []
        }
      },
      securitySchemes: {
        ApiKeyAuth: {
          type: "apiKey",
          in: "header",
          name: "X-API-Key"
        }
      }
    },
    security: [{ ApiKeyAuth: [] }]
  };
}
function getOpenAPIType(fieldType) {
  switch (fieldType) {
    case "string":
    case "text":
    case "email":
    case "url":
    case "date":
    case "datetime":
    case "select":
      return "string";
    case "number":
      return "number";
    case "boolean":
      return "boolean";
    case "multiselect":
      return "array";
    case "json":
      return "object";
    default:
      return "string";
  }
}
export {
  generateExternalAPI,
  generateOpenAPISpec
};
