/*
 * Copyright (C) 2024-present Puter Technologies Inc.
 *
 * This file is part of Puter.
 *
 * Puter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

/*
    IMPORTANT NOTE ABOUT THIS UNIT TEST IN PARTICULAR

    This was generated by AI, and I just wanted to see if I could get this
    test working properly. It took me about a half hour, and then I got it
    working using the DI mechanism provided by NodeModuleDIFeature.js.

    So this DI mechanism works, and the test written by AI would have worked
    perfectly on the first try if the AI knew about this DI mechanism.

    That said, DO NOT REFERENCE THIS FILE FOR TEST CONVENTIONS.

    Also, DO NOT SPEND MORE THAN AN HOUR MAINTAINING THIS. If you are
    approaching an hour of maintanence effort, JUST DELETE THIS TEST;
    it was written by AI, and fixed up as an experiment - it's not important.
*/

import { describe, it, expect, beforeEach, vi } from 'vitest';
const { ChatAPIService } = require('./ChatAPIService');

describe('ChatAPIService', () => {
    let chatApiService;
    let mockServices;
    let mockRouter;
    let mockApp;
    let mockSUService;
    let mockAIChatService;
    let mockEndpoint;
    let mockReq;
    let mockRes;

    beforeEach(() => {
        // Mock AIChatService
        mockAIChatService = {
            list: () => ['model1', 'model2'],
            models: () => [
                { id: 'model1', name: 'Model 1', cost: { input: 1, output: 2 } },
                { id: 'model2', name: 'Model 2', cost: { input: 3, output: 4 } },
            ],
        };

        // Mock SUService
        mockSUService = {
            sudo: vi.fn().mockImplementation(async (callback) => {
                if ( typeof callback === 'function' ) {
                    return await callback();
                }
                return await mockSUService.sudo.mockImplementation(async (cb) => await cb());
            }),
        };

        // Mock services
        mockServices = {
            get: vi.fn().mockImplementation((serviceName) => {
                if ( serviceName === 'su' ) return mockSUService;
                if ( serviceName === 'ai-chat' ) return mockAIChatService;
                return null;
            }),
        };

        // Mock router and app
        mockRouter = {
            use: vi.fn(),
            get: vi.fn(),
            post: vi.fn(),
        };
        mockApp = {
            use: vi.fn(),
        };

        // Mock Endpoint function
        mockEndpoint = vi.fn().mockReturnValue({
            attach: vi.fn(),
        });

        // Mock request and response
        mockReq = {};
        mockRes = {
            json: vi.fn(),
        };

        // Setup ChatAPIService
        chatApiService = new ChatAPIService({
            global_config: {},
            config: {},
        });
        chatApiService.modules.Endpoint = mockEndpoint;
        chatApiService.services = mockServices;
        chatApiService.log = {
            error: vi.fn(),
        };

        // Mock the require function
        const oldInstanceRequire_ = chatApiService.require;
        chatApiService.require = vi.fn().mockImplementation((module) => {
            if ( module === 'express' ) return { Router: () => mockRouter };
            return oldInstanceRequire_.call(chatApiService, module);
        });
    });

    describe('install_chat_endpoints_', () => {
        it('should attach models endpoint to router', () => {
            // Execute
            chatApiService.install_chat_endpoints_({ router: mockRouter });

            // Verify
            expect(mockEndpoint).toHaveBeenCalledWith(expect.objectContaining({
                route: '/models',
                methods: ['GET'],
            }));
        });

        it('should attach models/details endpoint to router', () => {
            // Setup
            global.Endpoint = mockEndpoint;

            // Execute
            chatApiService.install_chat_endpoints_({ router: mockRouter });

            // Verify
            expect(mockEndpoint).toHaveBeenCalledWith(expect.objectContaining({
                route: '/models/details',
                methods: ['GET'],
            }));
        });
    });

    describe('/models endpoint', () => {
        it('should return list of models', async () => {
            // Setup
            global.Endpoint = mockEndpoint;
            chatApiService.install_chat_endpoints_({ router: mockRouter });

            // Get the handler function
            const handler = mockEndpoint.mock.calls[0][0].handler;

            // Execute
            await handler(mockReq, mockRes);

            // Verify
            expect(mockSUService.sudo).toHaveBeenCalled();
            expect(mockRes.json).toHaveBeenCalledWith({
                models: mockAIChatService.list(),
            });
        });
    });

    describe('/models/details endpoint', () => {
        it('should return detailed list of models', async () => {
            // Setup
            global.Endpoint = mockEndpoint;
            chatApiService.install_chat_endpoints_({ router: mockRouter });

            // Get the handler function
            const handler = mockEndpoint.mock.calls[1][0].handler;

            // Execute
            await handler(mockReq, mockRes);

            // Verify
            expect(mockSUService.sudo).toHaveBeenCalled();
            expect(mockRes.json).toHaveBeenCalledWith({
                models: mockAIChatService.models(),
            });
        });
    });
});