import { DataSource } from 'typeorm';
import { Test, TestingModule } from '@nestjs/testing';
import { ConfigModule } from '@nestjs/config';
import { UserGroupsRepositoryModule } from '../../../repositories/user_groups/user_groups.repository.module';
import { TasksRepositoryModule } from '../../../repositories/tasks/tasks.repository.module';
import { AuthModule } from '../../../features/auth/auth.module';
import { AdB2cModule } from '../../../gateways/adb2c/adb2c.module';
import { AccountsModule } from '../../../features/accounts/accounts.module';
import { UsersModule } from '../../../features/users/users.module';
import { FilesModule } from '../../../features/files/files.module';
import { TasksModule } from '../../../features/tasks/tasks.module';
import { SendGridModule } from '../../../features/../gateways/sendgrid/sendgrid.module';
import { LicensesModule } from '../../../features/licenses/licenses.module';
import { AccountsRepositoryModule } from '../../../repositories/accounts/accounts.repository.module';
import { UsersRepositoryModule } from '../../../repositories/users/users.repository.module';
import { LicensesRepositoryModule } from '../../../repositories/licenses/licenses.repository.module';
import { AudioFilesRepositoryModule } from '../../../repositories/audio_files/audio_files.repository.module';
import { AudioOptionItemsRepositoryModule } from '../../../repositories/audio_option_items/audio_option_items.repository.module';
import { CheckoutPermissionsRepositoryModule } from '../../../repositories/checkout_permissions/checkout_permissions.repository.module';
import { NotificationModule } from '../../../features//notification/notification.module';
import { NotificationhubModule } from '../../../gateways/notificationhub/notificationhub.module';
import { BlobstorageModule } from '../../../gateways/blobstorage/blobstorage.module';
import { AuthGuardsModule } from '../../../common/guards/auth/authguards.module';
import { SortCriteriaRepositoryModule } from '../../../repositories/sort_criteria/sort_criteria.repository.module';
import { AuthService } from '../../../features/auth/auth.service';
import { AccountsService } from '../../../features/accounts/accounts.service';
import { UsersService } from '../../../features/users/users.service';
import { NotificationhubService } from '../../../gateways/notificationhub/notificationhub.service';
import { FilesService } from '../../../features/files/files.service';
import { LicensesService } from '../../../features/licenses/licenses.service';
import { TasksService } from '../../../features/tasks/tasks.service';
import { Task } from '../../../repositories/tasks/entity/task.entity';
import { AudioFile } from '../../../repositories/audio_files/entity/audio_file.entity';
import { BlobstorageService } from '../../../gateways/blobstorage/blobstorage.service';
import {
  BlobstorageServiceMockValue,
  makeBlobstorageServiceMock,
} from './files.service.mock';
import { TemplateFile } from '../../../repositories/template_files/entity/template_file.entity';
import {
  NotificationhubServiceMockValue,
  makeNotificationhubServiceMock,
} from '../../tasks/test/tasks.service.mock';
import { UserGroup } from '../../../repositories/user_groups/entity/user_group.entity';
import { UserGroupMember } from '../../../repositories/user_groups/entity/user_group_member.entity';
import { License } from '../../../repositories/licenses/entity/license.entity';

export const createTask = async (
  datasource: DataSource,
  account_id: number,
  url: string,
  fileName: string,
  status: string,
  typist_user_id?: number | undefined,
  author_id?: string | undefined,
): Promise<{ audioFileId: number }> => {
  const { identifiers: audioFileIdentifiers } = await datasource
    .getRepository(AudioFile)
    .insert({
      account_id: account_id,
      owner_user_id: 1,
      url: url,
      file_name: fileName,
      author_id: author_id ?? 'DEFAULT_ID',
      work_type_id: 'work_type_id',
      started_at: new Date(),
      duration: '100000',
      finished_at: new Date(),
      uploaded_at: new Date(),
      file_size: 10000,
      priority: '00',
      audio_format: 'audio_format',
      is_encrypted: true,
    });
  const audioFile = audioFileIdentifiers.pop() as AudioFile;
  const { identifiers: templateFileIdentifiers } = await datasource
    .getRepository(TemplateFile)
    .insert({
      account_id: account_id,
      url: url,
      file_name: fileName,
      created_by: 'test_runner',
      created_at: new Date(),
      updated_by: 'updater',
      updated_at: new Date(),
    });

  const templateFile = templateFileIdentifiers.pop() as TemplateFile;
  await datasource.getRepository(Task).insert({
    job_number: '00000001',
    account_id: account_id,
    is_job_number_enabled: true,
    audio_file_id: audioFile.id,
    template_file_id: templateFile.id,
    typist_user_id: typist_user_id,
    status: status,
    priority: '01',
    started_at: new Date().toISOString(),
    created_at: new Date(),
  });

  return { audioFileId: audioFile.id };
};

export const getTaskFromJobNumber = async (
  datasource: DataSource,
  jobNumber: string,
): Promise<Task | null> => {
  const task = await datasource.getRepository(Task).findOne({
    where: {
      job_number: jobNumber,
    },
  });
  return task;
};

// ユーザーグループとユーザーグループメンバーを作成する
export const createUserGroupAndMember = async (
  datasource: DataSource,
  accountId: number,
  name: string,
  userId: number,
): Promise<{ userGroupId: number }> => {
  const { identifiers } = await datasource.getRepository(UserGroup).insert({
    account_id: accountId,
    name: name,
    deleted_at: null,
    created_by: 'test_runner',
    created_at: new Date(),
    updated_by: 'updater',
    updated_at: new Date(),
  });
  const userGroup = identifiers.pop() as UserGroup;
  // ユーザーグループメンバーを作成する
  await datasource.getRepository(UserGroupMember).insert({
    user_group_id: userGroup.id,
    user_id: userId,
    created_by: 'test_runner',
    created_at: new Date(),
    updated_by: 'updater',
    updated_at: new Date(),
  });
  return { userGroupId: userGroup.id };
};

export const makeTestingModuleWithBlobAndNotification = async (
  datasource: DataSource,
  blobStorageService: BlobstorageServiceMockValue,
  notificationhubService: NotificationhubServiceMockValue,
): Promise<TestingModule | undefined> => {
  try {
    const module: TestingModule = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          envFilePath: ['.env.local', '.env'],
          isGlobal: true,
        }),
        AuthModule,
        AdB2cModule,
        AccountsModule,
        UsersModule,
        FilesModule,
        TasksModule,
        UsersModule,
        SendGridModule,
        LicensesModule,
        AccountsRepositoryModule,
        UsersRepositoryModule,
        LicensesRepositoryModule,
        AudioFilesRepositoryModule,
        AudioOptionItemsRepositoryModule,
        TasksRepositoryModule,
        CheckoutPermissionsRepositoryModule,
        UserGroupsRepositoryModule,
        UserGroupsRepositoryModule,
        NotificationModule,
        NotificationhubModule,
        BlobstorageModule,
        AuthGuardsModule,
        SortCriteriaRepositoryModule,
      ],
      providers: [
        AuthService,
        AccountsService,
        UsersService,
        NotificationhubService,
        FilesService,
        TasksService,
        LicensesService,
      ],
    })
      .useMocker(async (token) => {
        switch (token) {
          case DataSource:
            return datasource;
        }
      })
      .overrideProvider(BlobstorageService)
      .useValue(makeBlobstorageServiceMock(blobStorageService))
      .overrideProvider(NotificationhubService)
      .useValue(makeNotificationhubServiceMock(notificationhubService))
      .compile();

    return module;
  } catch (e) {
    console.log(e);
  }
};

export const createLicense = async (
  datasource: DataSource,
  licenseId: number,
  expiry_date: Date | null,
  accountId: number,
  type: string,
  status: string,
  allocated_user_id: number | null,
  order_id: number | null,
  deleted_at: Date | null,
  delete_order_id: number | null,
): Promise<void> => {
  const { identifiers } = await datasource.getRepository(License).insert({
    id: licenseId,
    expiry_date: expiry_date,
    account_id: accountId,
    type: type,
    status: status,
    allocated_user_id: allocated_user_id,
    order_id: order_id,
    deleted_at: deleted_at,
    delete_order_id: delete_order_id,
    created_by: 'test_runner',
    created_at: new Date(),
    updated_by: 'updater',
    updated_at: new Date(),
  });
  identifiers.pop() as License;
};
