import { DataSource } from 'typeorm';
import { makeTestingModule } from '../../common/test/modules';
import { TemplatesService } from './templates.service';
import { createTemplateFile } from './test/utility';
import { makeTestAccount } from '../../common/test/utility';
import { makeContext } from '../../common/log';
import { TemplateFilesRepositoryService } from '../../repositories/template_files/template_files.repository.service';
import { HttpException, HttpStatus } from '@nestjs/common';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { truncateAllTable } from '../../common/test/init';

describe('getTemplates', () => {
  let source: DataSource | null = null;
  beforeAll(async () => {
    if (source == null) {
      source = await (async () => {
        const s = new DataSource({
          type: 'mysql',
          host: 'test_mysql_db',
          port: 3306,
          username: 'user',
          password: 'password',
          database: 'odms',
          entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
          synchronize: false, // trueにすると自動的にmigrationが行われるため注意
        });
        return await s.initialize();
      })();
    }
  });

  beforeEach(async () => {
    if (source) {
      await truncateAllTable(source);
    }
  });

  afterAll(async () => {
    await source?.destroy();
    source = null;
  });

  it('テンプレートファイル一覧を取得できる', async () => {
    if (!source) fail();
    const module = await makeTestingModule(source);
    if (!module) fail();

    const service = module.get<TemplatesService>(TemplatesService);
    // 第五階層のアカウント作成
    const { account, admin } = await makeTestAccount(source, { tier: 5 });
    const context = makeContext(admin.external_id, 'requestId');

    const template1 = await createTemplateFile(
      source,
      account.id,
      'test1',
      'https://url1/test1',
    );
    const template2 = await createTemplateFile(
      source,
      account.id,
      'test2',
      'https://url2/test2',
    );

    // 作成したデータを確認
    {
      expect(template1.file_name).toBe('test1');
      expect(template2.file_name).toBe('test2');
    }

    const templates = await service.getTemplates(context, admin.external_id);

    //実行結果を確認
    {
      expect(templates.length).toBe(2);
      expect(templates[0].id).toBe(template1.id);
      expect(templates[0].name).toBe(template1.file_name);
      expect(templates[1].id).toBe(template2.id);
      expect(templates[1].name).toBe(template2.file_name);
    }
  });

  it('テンプレートファイル一覧を取得できる（0件）', async () => {
    if (!source) fail();
    const module = await makeTestingModule(source);
    if (!module) fail();

    const service = module.get<TemplatesService>(TemplatesService);
    // 第五階層のアカウント作成
    const { admin } = await makeTestAccount(source, { tier: 5 });
    const context = makeContext(admin.external_id, 'requestId');

    const templates = await service.getTemplates(context, admin.external_id);

    //実行結果を確認
    {
      expect(templates.length).toBe(0);
    }
  });

  it('テンプレートファイル一覧の取得に失敗した場合、エラーとなること', async () => {
    if (!source) fail();
    const module = await makeTestingModule(source);
    if (!module) fail();

    const service = module.get<TemplatesService>(TemplatesService);
    // 第五階層のアカウント作成
    const { admin } = await makeTestAccount(source, { tier: 5 });
    const context = makeContext(admin.external_id, 'requestId');

    //DBアクセスに失敗するようにする
    const typistGroupService = module.get<TemplateFilesRepositoryService>(
      TemplateFilesRepositoryService,
    );
    typistGroupService.getTemplateFiles = jest
      .fn()
      .mockRejectedValue('DB failed');

    try {
      await service.getTemplates(context, admin.external_id);
    } catch (e) {
      if (e instanceof HttpException) {
        expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
        expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
      } else {
        fail();
      }
    }
  });
});
