import { UserPermission } from '../../services/userManagementService/index.js';
import { CoopError, ErrorType } from '../../utils/errors.js';
import { logErrorJson } from '../../utils/logging.js';
import {
  type GQLMutationResolvers,
  type GQLQueryResolvers,
} from '../generated.js';
import { forbiddenError, unauthenticatedError } from '../utils/errors.js';
import { gqlErrorResult, gqlSuccessResult } from '../utils/gqlResult.js';

const typeDefs = /* GraphQL */ `
  type ApiKey {
    id: ID!
    name: String!
    description: String
    isActive: Boolean!
    createdAt: String!
    lastUsedAt: String
    createdBy: String
  }

  type RotateApiKeySuccessResponse {
    apiKey: String!
    record: ApiKey!
  }

  type RotateApiKeyError implements Error {
    title: String!
    status: Int!
    type: [String!]!
    pointer: String
    detail: String
    requestId: String
  }

  union RotateApiKeyResponse = RotateApiKeySuccessResponse | RotateApiKeyError

  input RotateApiKeyInput {
    name: String!
    description: String
  }

  type RotateWebhookSigningKeySuccessResponse {
    publicSigningKey: String!
  }

  type RotateWebhookSigningKeyError implements Error {
    title: String!
    status: Int!
    type: [String!]!
    pointer: String
    detail: String
    requestId: String
  }

  union RotateWebhookSigningKeyResponse =
    | RotateWebhookSigningKeySuccessResponse
    | RotateWebhookSigningKeyError

  type Query {
    apiKey: String!
  }

  type Mutation {
    rotateApiKey(input: RotateApiKeyInput!): RotateApiKeyResponse!
    rotateWebhookSigningKey: RotateWebhookSigningKeyResponse!
  }
`;

const Query: GQLQueryResolvers = {
  async apiKey(_, __, context) {
    const user = context.getUser();
    if (!user || !user.orgId) {
      throw unauthenticatedError('Authenticated user required');
    }
    if (!user.getPermissions().includes(UserPermission.MANAGE_ORG)) {
      throw forbiddenError(
        'User does not have permission to view the org API key',
      );
    }

    const apiKeyRecord =
      await context.services.ApiKeyService.getActiveApiKeyForOrg(user.orgId);
    if (!apiKeyRecord) {
      return process.env.NODE_ENV !== 'production' ? '' : '';
    }
    // Return a message indicating the key exists but is hidden for security
    return 'API key exists (hidden for security)';
  },
};

const Mutation: GQLMutationResolvers = {
  async rotateApiKey(_, { input }, context) {
    const user = context.getUser();
    if (!user || !user.orgId) {
      throw unauthenticatedError('Authenticated user required');
    }
    if (!user.getPermissions().includes(UserPermission.MANAGE_ORG)) {
      throw forbiddenError(
        'User does not have permission to rotate the API key',
      );
    }

    try {
      const { apiKey, record } =
        await context.services.ApiKeyService.rotateApiKey(
          user.orgId,
          input.name,
          input.description ?? null,
          user.id,
        );

      return gqlSuccessResult(
        {
          apiKey,
          record: {
            id: record.id,
            name: record.name,
            description: record.description,
            isActive: record.isActive,
            createdAt: record.createdAt.toISOString(),
            lastUsedAt: record.lastUsedAt?.toISOString() ?? null,
            createdBy: record.createdBy,
          },
        },
        'RotateApiKeySuccessResponse',
      );
    } catch (error) {
      // Resolvers do not receive a request-scoped logger; use logErrorJson for structured server-side logging.
      // eslint-disable-next-line no-restricted-syntax -- see comment above
      logErrorJson({ message: 'Failed to rotate API key', error });
      return gqlErrorResult(
        new CoopError({
          status: 500,
          type: [ErrorType.InternalServerError],
          title: 'Failed to rotate API key',
          detail: 'An error occurred while rotating the API key',
          name: 'RotateApiKeyError',
          shouldErrorSpan: true,
        }),
      );
    }
  },
  async rotateWebhookSigningKey(_, __, context) {
    const user = context.getUser();
    if (!user || !user.orgId) {
      throw unauthenticatedError('Authenticated user required');
    }
    if (!user.getPermissions().includes(UserPermission.MANAGE_ORG)) {
      throw forbiddenError(
        'User does not have permission to rotate the webhook signing key',
      );
    }

    try {
      const publicSigningKey =
        await context.dataSources.orgAPI.rotateWebhookSigningKey(user.orgId);
      return gqlSuccessResult(
        { publicSigningKey },
        'RotateWebhookSigningKeySuccessResponse',
      );
    } catch (error) {
      // Resolvers do not receive a request-scoped logger; use logErrorJson for structured server-side logging.
      // eslint-disable-next-line no-restricted-syntax -- see comment above
      logErrorJson({
        message: 'Failed to rotate webhook signing key',
        error,
      });
      return gqlErrorResult(
        new CoopError({
          status: 500,
          type: [ErrorType.InternalServerError],
          title: 'Failed to rotate webhook signing key',
          detail: 'An error occurred while rotating the webhook signing key',
          name: 'RotateWebhookSigningKeyError',
          shouldErrorSpan: true,
        }),
      );
    }
  },
};

export const resolvers = { Query, Mutation };
export { typeDefs, Query, Mutation };
