import { RuleTester } from 'eslint';
import tsParser from '@typescript-eslint/parser';
import test from 'node:test';
import rule from '../../src/eslint/rules/webhook-handler-requires-signature-verification.js';

const ruleTester = new RuleTester({
  languageOptions: {
    parser: tsParser,
    ecmaVersion: 2022,
    sourceType: 'module',
  },
});

const PARSE_FILENAME = '/repo/integrations/foo/src/handlers/parseWebhooks.ts';
const PARSE_FILENAME_ALT = '/repo/integrations/foo/src/routes/webhookParse.ts';
const NON_WEBHOOK_FILENAME = '/repo/integrations/foo/src/handlers/task.ts';

test('webhook-handler-requires-signature-verification', () => {
  ruleTester.run('webhook-handler-requires-signature-verification', rule, {
    valid: [
      {
        name: 'parseWebhooks.ts importing node:crypto verifier helpers',
        filename: PARSE_FILENAME,
        code: `
          import { createHmac, timingSafeEqual } from 'node:crypto';
          import { ParseWebhooksHandler } from '@unito/integration-sdk';
          export const parseWebhooks: ParseWebhooksHandler = async (ctx) => {
            return [];
          };
        `,
      },
      {
        name: 'webhookParse.ts importing legacy `crypto` module',
        filename: PARSE_FILENAME_ALT,
        code: `
          import * as crypto from 'crypto';
          import { ParseWebhooksHandler } from '@unito/integration-sdk';
          export const parseWebhooks: ParseWebhooksHandler = async (ctx) => {
            return [];
          };
        `,
      },
      {
        name: 'parseWebhooks.ts with @webhook-no-signature opt-out',
        filename: PARSE_FILENAME,
        code: `
          import { ParseWebhooksHandler } from '@unito/integration-sdk';
          /** @webhook-no-signature: provider does not sign webhooks (legacy ServiceNow business rule) */
          export const parseWebhooks: ParseWebhooksHandler = async (ctx) => {
            return [];
          };
        `,
      },
      {
        name: 'AcknowledgeWebhooksHandler export is out of scope',
        filename: '/repo/integrations/foo/src/handlers/webhookAcknowledge.ts',
        code: `
          import { AcknowledgeWebhooksHandler } from '@unito/integration-sdk';
          export const acknowledgeWebhooks: AcknowledgeWebhooksHandler = async (ctx) => {
            return { handshake: 'ok' };
          };
        `,
      },
      {
        name: 'non-webhook file is out of scope',
        filename: NON_WEBHOOK_FILENAME,
        code: `
          import { GetItemHandler } from '@unito/integration-sdk';
          export const getTask: GetItemHandler = async (ctx) => ({});
        `,
      },
      {
        name: 'arbitrary file that imports ParseWebhooksHandler with verifier (in-scope by import)',
        filename: '/repo/integrations/foo/src/helpers/webhookHelper.ts',
        code: `
          import { createHmac } from 'node:crypto';
          import { ParseWebhooksHandler } from '@unito/integration-sdk';
          export const parseWebhooks: ParseWebhooksHandler = async (ctx) => [];
        `,
      },
      {
        name: 'parseWebhooks.ts importing SDK verifier helper by name',
        filename: PARSE_FILENAME,
        code: `
          import { ParseWebhooksHandler, verifyWebhookSignature } from '@unito/integration-sdk';
          export const parseWebhooks: ParseWebhooksHandler = async (ctx) => {
            verifyWebhookSignature(ctx.body.headers, ctx.body.payload);
            return [];
          };
        `,
      },
      {
        name: 'webhookParse.ts only an Acknowledge export plus crypto-less helper imports',
        filename: '/repo/integrations/foo/src/handlers/webhookSubscriptions.ts',
        code: `
          import { AcknowledgeWebhooksHandler } from '@unito/integration-sdk';
          export const acknowledgeWebhooks: AcknowledgeWebhooksHandler = async (ctx) => ({});
        `,
      },
    ],
    invalid: [
      {
        name: 'parseWebhooks.ts exporting ParseWebhooksHandler with no crypto import',
        filename: PARSE_FILENAME,
        code: `
          import { ParseWebhooksHandler } from '@unito/integration-sdk';
          export const parseWebhooks: ParseWebhooksHandler = async (ctx) => {
            const payload = JSON.parse(ctx.body.payload);
            return [];
          };
        `,
        errors: [{ messageId: 'missingVerification', data: { name: 'parseWebhooks' } }],
      },
      {
        name: 'webhookParse.ts (alternate name) with no verifier import',
        filename: PARSE_FILENAME_ALT,
        code: `
          import { ParseWebhooksHandler, ParseWebhooksContext } from '@unito/integration-sdk';
          export const parseWebhooks: ParseWebhooksHandler = async (ctx: ParseWebhooksContext) => {
            return [];
          };
        `,
        errors: [{ messageId: 'missingVerification', data: { name: 'parseWebhooks' } }],
      },
      {
        name: 'parseWebhooks.ts with raw JSON.parse and no signature check',
        filename: PARSE_FILENAME,
        code: `
          import { ParseWebhooksHandler } from '@unito/integration-sdk';
          export const parseWebhooks: ParseWebhooksHandler = async (ctx) => {
            const data = JSON.parse(ctx.body.payload);
            return data.events.map((e) => ({ itemPath: '/x', date: '', impactedRelations: [] }));
          };
        `,
        errors: [{ messageId: 'missingVerification', data: { name: 'parseWebhooks' } }],
      },
      {
        name: 'arbitrary filename in-scope by ParseWebhooksHandler import only',
        filename: '/repo/integrations/foo/src/helpers/somethingElse.ts',
        code: `
          import { ParseWebhooksHandler } from '@unito/integration-api';
          export const parseWebhooks: ParseWebhooksHandler = async () => [];
        `,
        errors: [{ messageId: 'missingVerification', data: { name: 'parseWebhooks' } }],
      },
      {
        name: 'parseWebhooks.ts opt-out without reason is rejected',
        filename: PARSE_FILENAME,
        code: `
          import { ParseWebhooksHandler } from '@unito/integration-sdk';
          /** @webhook-no-signature: */
          export const parseWebhooks: ParseWebhooksHandler = async (ctx) => [];
        `,
        errors: [{ messageId: 'missingVerification', data: { name: 'parseWebhooks' } }],
      },
      {
        name: 'parseWebhooks.ts inferred from export name even without type annotation',
        filename: PARSE_FILENAME,
        code: `
          export const parseWebhooks = async (ctx) => {
            return [];
          };
        `,
        errors: [{ messageId: 'missingVerification', data: { name: 'parseWebhooks' } }],
      },
      {
        name: 'parseWebhooks.ts with non-crypto import still flagged',
        filename: PARSE_FILENAME,
        code: `
          import { JSON5 } from 'some-other-pkg';
          import { ParseWebhooksHandler } from '@unito/integration-sdk';
          export const parseWebhooks: ParseWebhooksHandler = async (ctx) => {
            return JSON5.parse(ctx.body.payload);
          };
        `,
        errors: [{ messageId: 'missingVerification', data: { name: 'parseWebhooks' } }],
      },
      {
        name: 'webhookParse.ts with separate const decl and `export { parseWebhooks }` form',
        filename: PARSE_FILENAME_ALT,
        code: `
          import { ParseWebhooksHandler, ParseWebhooksContext } from '@unito/integration-sdk';
          const parseWebhooks: ParseWebhooksHandler = async (ctx: ParseWebhooksContext) => {
            return [];
          };
          export { parseWebhooks };
        `,
        errors: [{ messageId: 'missingVerification', data: { name: 'parseWebhooks' } }],
      },
      {
        name: 'Express-route webhookParse.ts: only exports a `router` but file is in scope by filename',
        filename: '/repo/integrations/foo/src/routes/webhookParse.ts',
        code: `
          import { Router } from 'express';
          export const router = Router();
          router.post('/', async (req, res) => {
            res.json({});
          });
        `,
        errors: [{ messageId: 'missingVerification', data: { name: '<webhook-parse-route>' } }],
      },
    ],
  });
});
