import { TemplateApi } from '../../api/templateApi';
import * as sinon from 'sinon';

describe('TemplateApi Unit Test', () => {
    let templateApiStub: sinon.SinonStubbedInstance<TemplateApi>;

    beforeEach(() => {
        // Create a stub instance of TemplateApi
        templateApiStub = sinon.createStubInstance(TemplateApi);
    });

    afterEach(() => {
        sinon.restore();
    });

    it('should mock and verify createTemplate call', async () => {
        const templateData = {
            name: 'Sample Template',
            fields: {
                Title: 'title',
                Description: 'description',
                DocumentTitle: 'documentTitle',
                Files: 'path/to/file.png',
                BrandId: 'brand_id',
                onBehalfOf: 'email_example',
            }
        };

        const mockCreatedTemplate = {
            id: 'templateId',
            name: 'Sample Template'
        };

        templateApiStub.createTemplate.resolves(mockCreatedTemplate);

        const result = await templateApiStub.createTemplate(templateData);

        expect(result.id).toEqual('templateId');

        sinon.assert.calledOnceWithExactly(templateApiStub.createTemplate, templateData);
    });

    it('should mock and verify listTemplates call', async () => {
        const mockTemplatesList = [
            { id: 'template1', name: 'Template One' },
            { id: 'template2', name: 'Template Two' }
        ];

        templateApiStub.listTemplates.resolves(mockTemplatesList);

        const result = await templateApiStub.listTemplates();

        expect(result).toBeDefined();
        expect(Array.isArray(result)).toBe(true);
        expect(result.length).toBe(2);
        expect(result[0].id).toBe('template1');
        expect(result[1].name).toBe('Template Two');

        sinon.assert.calledOnce(templateApiStub.listTemplates);
    });

    it('should mock and verify deleteTemplate call', async () => {
        const templateId = 'templateIdToDelete';

        const mockDeleteResponse = {
            success: true,
            message: 'Template deleted successfully'
        };

        templateApiStub.deleteTemplate.resolves(mockDeleteResponse);

        const result = await templateApiStub.deleteTemplate(templateId);

        expect(result).toBeDefined();
        expect(result.success).toBe(true);
        expect(result.message).toBe('Template deleted successfully');

        sinon.assert.calledOnceWithExactly(templateApiStub.deleteTemplate, templateId);
    });

    it('should mock and verify getTemplateDetails call', async () => {
        const templateId = 'template123';
        const mockTemplateDetails = {
            id: 'template123',
            name: 'Detailed Template',
            fields: {
                Title: 'Sample Title',
                Description: 'Some description'
            }
        };
    
        templateApiStub.getTemplateDetails = sinon.stub().resolves(mockTemplateDetails);
    
        const result = await templateApiStub.getTemplateDetails(templateId);
    
        expect(result).toBeDefined();
        expect(result.id).toBe('template123');
        expect(result.name).toBe('Detailed Template');
    
        sinon.assert.calledOnceWithExactly(templateApiStub.getTemplateDetails, templateId);
    });

    it('should mock and verify editTemplate (updateTemplate) call', async () => {
        const templateId = 'template123';
        const updateData = {
            name: 'Updated Template',
            fields: {
                Title: 'Updated Title',
                Description: 'Updated description',
                DocumentTitle: 'Updated documentTitle',
                Files: 'path/to/updated_file.png',
                BrandId: 'updated_brand_id',
                onBehalfOf: 'updated_email@example.com',
            }
        };
    
        const mockUpdatedTemplate = {
            id: 'template123',
            name: 'Updated Template',
            fields: updateData.fields
        };
    
        templateApiStub.updateTemplate = sinon.stub().resolves(mockUpdatedTemplate);
    
        const result = await templateApiStub.updateTemplate(templateId, updateData);
    
        expect(result).toBeDefined();
        expect(result.id).toBe(templateId);
        expect(result.name).toBe('Updated Template');
    
        sinon.assert.calledOnceWithExactly(templateApiStub.updateTemplate, templateId, updateData);
    });

    it('should mock and verify addTemplateTag call', async () => {
        const templateId = 'template123';
        const tagData = {
            tag: 'new-tag',
        };

        const mockAddTagResponse = {
            success: true,
            message: 'Tag added successfully to the template',
            templateId: 'template123',
            tags: ['new-tag'],
        };

        templateApiStub.addTemplateTag = sinon.stub().resolves(mockAddTagResponse);

        const result = await templateApiStub.addTemplateTag(templateId, tagData);

        expect(result).toBeDefined();
        expect(result.success).toBe(true);
        expect(result.message).toBe('Tag added successfully to the template');
        expect(result.templateId).toBe(templateId);
        expect(result.tags).toEqual(['new-tag']);

        sinon.assert.calledOnceWithExactly(templateApiStub.addTemplateTag, templateId, tagData);
    });

    it('should mock and verify deleteTemplateTag call', async () => {
        const templateId = 'template123';
        const tagData = {
            tag: 'new-tag',
        };

        const mockDeleteTagResponse = {
            success: true,
            message: 'Tag deleted successfully from the template',
            templateId: 'template123',
            tags: [],
        };

        templateApiStub.deleteTemplateTag = sinon.stub().resolves(mockDeleteTagResponse);

        const result = await templateApiStub.deleteTemplateTag(templateId, tagData);

        expect(result).toBeDefined();
        expect(result.success).toBe(true);
        expect(result.message).toBe('Tag deleted successfully from the template');
        expect(result.templateId).toBe(templateId);
        expect(result.tags).toEqual([]);

        sinon.assert.calledOnceWithExactly(templateApiStub.deleteTemplateTag, templateId, tagData);
    });

    it('should mock and verify downloadTemplate call', async () => {
        const templateId = 'template123';
        const mockDownloadResponse = Buffer.from('some template data');

        templateApiStub.downloadTemplate = sinon.stub().resolves(mockDownloadResponse);

        const result = await templateApiStub.downloadTemplate(templateId);

        expect(result).toBeDefined();
        expect(result).toBeInstanceOf(Buffer);
        expect(result.toString()).toBe(mockDownloadResponse.toString());

        sinon.assert.calledOnceWithExactly(templateApiStub.downloadTemplate, templateId);
    });

    it('should mock and verify createEmbeddedTemplate call', async () => {
        const embeddedTemplateData = {
            name: 'Embedded Template',
            fields: {
                Title: 'title',
                Description: 'description',
                DocumentTitle: 'documentTitle',
                Files: 'path/to/file.pdf',
                BrandId: 'brand123',
                onBehalfOf: 'user@example.com',
            },
            redirectUrl: 'https://your-app.com/redirect',
        };

        const mockEmbeddedTemplateResponse = {
            templateId: 'embeddedTemplate123',
            url: 'https://signing-service.com/embedded/template/embeddedTemplate123',
            expiresAt: '2025-12-31T23:59:59Z'
        };

        templateApiStub.createEmbeddedTemplate = sinon.stub().resolves(mockEmbeddedTemplateResponse);

        const result = await templateApiStub.createEmbeddedTemplate(embeddedTemplateData);

        expect(result).toBeDefined();
        expect(result.templateId).toBe('embeddedTemplate123');
        expect(result.url).toContain('/embedded/template/embeddedTemplate123');
        expect(result.expiresAt).toBe('2025-12-31T23:59:59Z');

        sinon.assert.calledOnceWithExactly(templateApiStub.createEmbeddedTemplate, embeddedTemplateData);
    });

    it('should mock and verify editEmbeddedTemplate call', async () => {
        const templateId = 'embeddedTemplate123';
        const updateData = {
            name: 'Updated Embedded Template',
            fields: {
                Title: 'Updated Title',
                Description: 'Updated Description',
                DocumentTitle: 'Updated Doc Title',
                Files: 'path/to/updated_file.pdf',
                BrandId: 'updatedBrand456',
                onBehalfOf: 'updateduser@example.com',
            },
            redirectUrl: 'https://your-app.com/updated-redirect',
        };

        const mockUpdatedEmbeddedTemplateResponse = {
            templateId: templateId,
            name: 'Updated Embedded Template',
            url: 'https://signing-service.com/embedded/template/embeddedTemplate123',
            expiresAt: '2025-12-31T23:59:59Z',
            updated: true
        };

        templateApiStub.editEmbeddedTemplate = sinon.stub().resolves(mockUpdatedEmbeddedTemplateResponse);

        const result = await templateApiStub.editEmbeddedTemplate(templateId, updateData);

        expect(result).toBeDefined();
        expect(result.templateId).toBe(templateId);
        expect(result.name).toBe('Updated Embedded Template');
        expect(result.url).toContain('/embedded/template/embeddedTemplate123');
        expect(result.updated).toBe(true);
        expect(result.expiresAt).toBe('2025-12-31T23:59:59Z');

        sinon.assert.calledOnceWithExactly(templateApiStub.editEmbeddedTemplate, templateId, updateData);
    });

    it('should mock and verify createEmbeddedRequestLinkFromTemplate call', async () => {
        const templateId = 'template123';
        const requestData = {
            title: 'Embedded Signing Request',
            message: 'Please sign this document via embedded link.',
            roles: [
                {
                    role: 'Signer',
                    name: 'Jane Doe',
                    email: 'jane.doe@example.com',
                }
            ],
            redirectUrl: 'https://your-app.com/redirect-after-signing',
            onBehalfOf: 'admin@example.com',
            isSandbox: true,
            labels: ['embedded', 'request'],
        };

        const mockResponse = {
            requestId: 'req789',
            url: 'https://signing-service.com/embedded/request/req789',
            expiresAt: '2025-12-31T23:59:59Z',
            templateId: 'template123',
        };

        templateApiStub.createEmbeddedRequestLinkFromTemplate = sinon.stub().resolves(mockResponse);

        const result = await templateApiStub.createEmbeddedRequestLinkFromTemplate(templateId, requestData);

        expect(result).toBeDefined();
        expect(result.requestId).toBe('req789');
        expect(result.url).toContain('/embedded/request/req789');
        expect(result.templateId).toBe(templateId);
        expect(result.expiresAt).toBe('2025-12-31T23:59:59Z');

        sinon.assert.calledOnceWithExactly(templateApiStub.createEmbeddedRequestLinkFromTemplate, templateId, requestData);
    });
});