/**
 * @ai-summary Unit tests for tier validation in DocumentsController
 * @ai-context Tests that free users cannot use scanForMaintenance feature
 */

// Mock config and dependencies first (before any imports that might use them)
jest.mock('../../../../core/config/config-loader', () => ({
  appConfig: {
    getDatabaseUrl: () => 'postgresql://mock:mock@localhost/mock',
    getRedisUrl: () => 'redis://localhost',
    get: () => ({}),
  },
  config: {
    database: { connectionString: 'mock' },
    redis: { url: 'mock' },
    auth0: { domain: 'mock', clientId: 'mock', audience: 'mock' },
    storage: { provider: 'filesystem', root: '/tmp' },
    logging: { level: 'error' },
  },
}));
jest.mock('../../../../core/config/database', () => ({
  pool: {
    query: jest.fn(),
    connect: jest.fn(),
    end: jest.fn(),
  },
  default: {
    query: jest.fn(),
    connect: jest.fn(),
    end: jest.fn(),
  },
}));
jest.mock('../../../../core/logging/logger', () => ({
  logger: {
    info: jest.fn(),
    warn: jest.fn(),
    error: jest.fn(),
    debug: jest.fn(),
  },
}));
jest.mock('../../../../core/storage/storage.service', () => ({
  getStorageService: jest.fn(() => ({
    putObject: jest.fn(),
    getObjectStream: jest.fn(),
    deleteObject: jest.fn(),
    headObject: jest.fn(),
  })),
}));
jest.mock('../../domain/documents.service');

import { FastifyRequest, FastifyReply } from 'fastify';
import { DocumentsController } from '../../api/documents.controller';
import { DocumentsService } from '../../domain/documents.service';

const MockedService = jest.mocked(DocumentsService);

describe('DocumentsController - Tier Validation', () => {
  let controller: DocumentsController;
  let mockServiceInstance: jest.Mocked<DocumentsService>;

  const createMockRequest = (overrides: Partial<FastifyRequest> = {}): FastifyRequest => ({
    user: { sub: 'user-123' },
    userContext: {
      userId: 'user-123',
      email: 'test@example.com',
      emailVerified: true,
      onboardingCompleted: true,
      isAdmin: false,
      subscriptionTier: 'free',
    },
    body: {},
    params: {},
    query: {},
    ...overrides,
  } as unknown as FastifyRequest);

  const createMockReply = (): Partial<FastifyReply> & { payload?: unknown; statusCode?: number } => ({
    sent: false,
    code: jest.fn(function(this: any, status: number) {
      this.statusCode = status;
      return this;
    }),
    send: jest.fn(function(this: any, payload: unknown) {
      this.payload = payload;
      this.sent = true;
      return this;
    }),
  });

  beforeEach(() => {
    jest.clearAllMocks();

    mockServiceInstance = {
      createDocument: jest.fn(),
      updateDocument: jest.fn(),
      getDocument: jest.fn(),
      listDocuments: jest.fn(),
      deleteDocument: jest.fn(),
    } as any;

    MockedService.mockImplementation(() => mockServiceInstance);
    controller = new DocumentsController();
  });

  describe('create - scanForMaintenance tier gating', () => {
    const baseDocumentBody = {
      vehicleId: 'vehicle-123',
      documentType: 'manual',
      title: 'Service Manual',
    };

    it('allows free user to create document without scanForMaintenance', async () => {
      const request = createMockRequest({
        body: { ...baseDocumentBody, scanForMaintenance: false },
      });
      const reply = createMockReply();

      mockServiceInstance.createDocument.mockResolvedValue({
        id: 'doc-123',
        userId: 'user-123',
        vehicleId: 'vehicle-123',
        documentType: 'manual',
        title: 'Service Manual',
        scanForMaintenance: false,
      } as any);

      await controller.create(request as any, reply as FastifyReply);

      expect(reply.code).toHaveBeenCalledWith(201);
      expect(mockServiceInstance.createDocument).toHaveBeenCalled();
    });

    it('blocks free user from using scanForMaintenance=true', async () => {
      const request = createMockRequest({
        body: { ...baseDocumentBody, scanForMaintenance: true },
      });
      const reply = createMockReply();

      await controller.create(request as any, reply as FastifyReply);

      expect(reply.code).toHaveBeenCalledWith(403);
      expect(reply.send).toHaveBeenCalledWith(
        expect.objectContaining({
          error: 'TIER_REQUIRED',
          requiredTier: 'pro',
          currentTier: 'free',
          feature: 'document.scanMaintenanceSchedule',
          featureName: 'Scan for Maintenance Schedule',
        })
      );
      expect(mockServiceInstance.createDocument).not.toHaveBeenCalled();
    });

    it('allows pro user to use scanForMaintenance=true', async () => {
      const request = createMockRequest({
        body: { ...baseDocumentBody, scanForMaintenance: true },
        userContext: {
          userId: 'user-123',
          email: 'pro@example.com',
          emailVerified: true,
          onboardingCompleted: true,
          isAdmin: false,
          subscriptionTier: 'pro',
        },
      });
      const reply = createMockReply();

      mockServiceInstance.createDocument.mockResolvedValue({
        id: 'doc-123',
        userId: 'user-123',
        vehicleId: 'vehicle-123',
        documentType: 'manual',
        title: 'Service Manual',
        scanForMaintenance: true,
      } as any);

      await controller.create(request as any, reply as FastifyReply);

      expect(reply.code).toHaveBeenCalledWith(201);
      expect(mockServiceInstance.createDocument).toHaveBeenCalled();
    });

    it('allows enterprise user to use scanForMaintenance=true', async () => {
      const request = createMockRequest({
        body: { ...baseDocumentBody, scanForMaintenance: true },
        userContext: {
          userId: 'user-123',
          email: 'enterprise@example.com',
          emailVerified: true,
          onboardingCompleted: true,
          isAdmin: false,
          subscriptionTier: 'enterprise',
        },
      });
      const reply = createMockReply();

      mockServiceInstance.createDocument.mockResolvedValue({
        id: 'doc-123',
        userId: 'user-123',
        vehicleId: 'vehicle-123',
        documentType: 'manual',
        title: 'Service Manual',
        scanForMaintenance: true,
      } as any);

      await controller.create(request as any, reply as FastifyReply);

      expect(reply.code).toHaveBeenCalledWith(201);
      expect(mockServiceInstance.createDocument).toHaveBeenCalled();
    });

    it('defaults to free tier when userContext is missing', async () => {
      const request = createMockRequest({
        body: { ...baseDocumentBody, scanForMaintenance: true },
        userContext: undefined,
      });
      const reply = createMockReply();

      await controller.create(request as any, reply as FastifyReply);

      expect(reply.code).toHaveBeenCalledWith(403);
      expect(reply.send).toHaveBeenCalledWith(
        expect.objectContaining({
          error: 'TIER_REQUIRED',
          currentTier: 'free',
        })
      );
    });
  });

  describe('update - scanForMaintenance tier gating', () => {
    const documentId = 'doc-123';

    it('allows free user to update document without scanForMaintenance', async () => {
      const request = createMockRequest({
        params: { id: documentId },
        body: { title: 'Updated Title' },
      });
      const reply = createMockReply();

      mockServiceInstance.updateDocument.mockResolvedValue({
        id: documentId,
        title: 'Updated Title',
      } as any);

      await controller.update(request as any, reply as FastifyReply);

      expect(reply.code).toHaveBeenCalledWith(200);
      expect(mockServiceInstance.updateDocument).toHaveBeenCalled();
    });

    it('blocks free user from setting scanForMaintenance=true on update', async () => {
      const request = createMockRequest({
        params: { id: documentId },
        body: { scanForMaintenance: true },
      });
      const reply = createMockReply();

      await controller.update(request as any, reply as FastifyReply);

      expect(reply.code).toHaveBeenCalledWith(403);
      expect(reply.send).toHaveBeenCalledWith(
        expect.objectContaining({
          error: 'TIER_REQUIRED',
          requiredTier: 'pro',
          currentTier: 'free',
          feature: 'document.scanMaintenanceSchedule',
        })
      );
      expect(mockServiceInstance.updateDocument).not.toHaveBeenCalled();
    });

    it('allows pro user to set scanForMaintenance=true on update', async () => {
      const request = createMockRequest({
        params: { id: documentId },
        body: { scanForMaintenance: true },
        userContext: {
          userId: 'user-123',
          email: 'pro@example.com',
          emailVerified: true,
          onboardingCompleted: true,
          isAdmin: false,
          subscriptionTier: 'pro',
        },
      });
      const reply = createMockReply();

      mockServiceInstance.updateDocument.mockResolvedValue({
        id: documentId,
        scanForMaintenance: true,
      } as any);

      await controller.update(request as any, reply as FastifyReply);

      expect(reply.code).toHaveBeenCalledWith(200);
      expect(mockServiceInstance.updateDocument).toHaveBeenCalled();
    });
  });
});
