import {
  INestApplication,
  UnauthorizedException,
  ValidationPipe,
  VersioningType,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import validationOptions from '../utils/validation-options';
import { TransactionTypeEnum } from '../transactions/transaction-type.enum';
import { RecurringTransactionIntervalEnum } from './recurring-transaction-interval.enum';
import { RecurringTransactionsController } from './recurring-transactions.controller';
import { RecurringTransactionsService } from './recurring-transactions.service';

describe('recurring transactions HTTP boundary', () => {
  let app: INestApplication;
  const entry = {
    id: 8,
    description: 'Monatsbeitrag',
    amount: 10,
    type: TransactionTypeEnum.fee,
    interval: RecurringTransactionIntervalEnum.monthly,
    nextRunDate: '2026-09-01T00:00:00.000Z',
    active: true,
    createdAt: '2026-01-02T00:00:00.000Z',
  };
  const service = {
    getTeamRecurringTransactions: jest.fn(() => [entry]),
    createRecurringTransaction: jest.fn(() => entry),
    updateRecurringTransaction: jest.fn(() => entry),
    deleteRecurringTransaction: jest.fn(),
  };

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      controllers: [RecurringTransactionsController],
      providers: [
        { provide: RecurringTransactionsService, useValue: service },
      ],
    })
      .overrideGuard(AuthGuard('jwt'))
      .useValue({
        canActivate(context) {
          const httpRequest = context.switchToHttp().getRequest();
          if (httpRequest.headers.authorization !== 'Bearer user') {
            throw new UnauthorizedException();
          }
          httpRequest.user = { id: 42, role: { id: 2 } };
          return true;
        },
      })
      .compile();
    app = module.createNestApplication();
    app.setGlobalPrefix('api');
    app.enableVersioning({ type: VersioningType.URI });
    app.useGlobalPipes(new ValidationPipe(validationOptions));
    await app.init();
  });

  afterAll(() => app.close());
  beforeEach(() => jest.clearAllMocks());

  it('requires authentication for team reads', async () => {
    await request(app.getHttpServer())
      .get('/api/v1/recurring-transactions/5')
      .expect(401);
    await request(app.getHttpServer())
      .get('/api/v1/recurring-transactions/5')
      .set('Authorization', 'Bearer user')
      .expect(200)
      .expect([entry]);
    expect(service.getTeamRecurringTransactions).toHaveBeenCalledWith(42, 5);
  });

  it('rejects a create payload with a disallowed transaction type', async () => {
    await request(app.getHttpServer())
      .post('/api/v1/recurring-transactions')
      .set('Authorization', 'Bearer user')
      .send({
        teamId: 5,
        description: 'Monatsbeitrag',
        amount: 10,
        type: TransactionTypeEnum.payment,
        interval: RecurringTransactionIntervalEnum.monthly,
        startDate: '2026-09-01T00:00:00.000Z',
      })
      .expect(422);
    expect(service.createRecurringTransaction).not.toHaveBeenCalled();
  });

  it('accepts a valid create payload and forwards the actor', async () => {
    await request(app.getHttpServer())
      .post('/api/v1/recurring-transactions')
      .set('Authorization', 'Bearer user')
      .send({
        teamId: 5,
        description: 'Monatsbeitrag',
        amount: 10,
        type: TransactionTypeEnum.fee,
        interval: RecurringTransactionIntervalEnum.monthly,
        startDate: '2026-09-01T00:00:00.000Z',
      })
      .expect(201)
      .expect(entry);
    expect(service.createRecurringTransaction).toHaveBeenCalledWith(
      {
        teamId: 5,
        description: 'Monatsbeitrag',
        amount: 10,
        type: TransactionTypeEnum.fee,
        interval: RecurringTransactionIntervalEnum.monthly,
        startDate: '2026-09-01T00:00:00.000Z',
      },
      42,
    );
  });

  it('updates and deletes by id', async () => {
    await request(app.getHttpServer())
      .patch('/api/v1/recurring-transactions/8')
      .set('Authorization', 'Bearer user')
      .send({
        description: 'Monatsbeitrag',
        amount: 12,
        type: TransactionTypeEnum.levy,
        interval: RecurringTransactionIntervalEnum.quarterly,
        active: false,
      })
      .expect(200)
      .expect(entry);
    expect(service.updateRecurringTransaction).toHaveBeenCalledWith(
      8,
      {
        description: 'Monatsbeitrag',
        amount: 12,
        type: TransactionTypeEnum.levy,
        interval: RecurringTransactionIntervalEnum.quarterly,
        active: false,
      },
      42,
    );

    await request(app.getHttpServer())
      .delete('/api/v1/recurring-transactions/8')
      .set('Authorization', 'Bearer user')
      .expect(204);
    expect(service.deleteRecurringTransaction).toHaveBeenCalledWith(8, 42);
  });
});
