import { Task as TaskEntity } from '../../../repositories/tasks/entity/task.entity';
import { User as UserEntity } from '../../../repositories/users/entity/user.entity';
import { UserGroup as UserGroupEntity } from '../../../repositories/user_groups/entity/user_group.entity';
import { CheckoutPermission as CheckoutPermissionEntity } from '../../../repositories/checkout_permissions/entity/checkout_permission.entity';
import { AudioOptionItem as AudioOptionItemEntity } from '../../../repositories/audio_option_items/entity/audio_option_item.entity';
import { Task, Assignee } from './types';
import { AudioOptionItem } from '../../files/types/types';
import { Typist } from '../../../features/accounts/types/types';
import { AdB2cUser } from '../../../gateways/adb2c/types/types';

// Repository側のDTOからTaskオブジェクトの一覧を構築する
export const createTasks = (
  tasks: TaskEntity[],
  permissions: CheckoutPermissionEntity[],
  b2cUsers: AdB2cUser[],
): Task[] => {
  // Taskオブジェクトを構築
  const convertedTasks = tasks.map((task) => {
    const targets = permissions.filter(
      (permission) => permission.task_id === task.id,
    );
    return createTask(task, targets, b2cUsers);
  });
  return convertedTasks;
};

// Repository側のDTOからTaskオブジェクトを構築する
const createTask = (
  task: TaskEntity,
  permissions: CheckoutPermissionEntity[],
  b2cUserInfo: AdB2cUser[],
): Task => {
  const { file, option_items, typist_user } = task;
  if (!file) {
    throw new Error('file not found.');
  }
  if (!option_items) {
    throw new Error('option_items not found.');
  }

  // RepositoryDTO => ControllerDTOに変換
  const optionItems = createAudioOptionItems(option_items);

  // RepositoryDTO => ControllerDTOに変換
  const assignees = createAssignees(permissions, b2cUserInfo);

  // RepositoryDTO => ControllerDTOに変換
  const typist: Typist =
    typist_user != null
      ? convertUserToTypist(typist_user, b2cUserInfo)
      : undefined;

  return {
    audioFileId: task.audio_file_id,
    priority: task.priority,
    status: task.status,
    jobNumber: task.job_number,
    transcriptionFinishedDate: task.finished_at?.toISOString(),
    transcriptionStartedDate: task.started_at?.toISOString(),
    authorId: file.author_id,
    workType: file.work_type_id,
    audioCreatedDate: file.started_at.toISOString(),
    audioDuration: file.duration,
    audioFinishedDate: file.finished_at.toISOString(),
    audioUploadedDate: file.uploaded_at.toISOString(),
    audioFormat: file.audio_format,
    comment: file.comment ?? '',
    fileName: file.file_name,
    fileSize: file.file_size,
    isEncrypted: file.is_encrypted,
    url: file.url,
    optionItemList: optionItems,
    assignees: assignees,
    typist: typist,
  };
};

// Repository側のDTOからAudioOptionItemオブジェクトを構築する
const createAudioOptionItems = (
  optionItems: AudioOptionItemEntity[],
): AudioOptionItem[] => {
  return optionItems.map((x) => {
    return {
      optionItemLabel: x.label,
      optionItemValue: x.value,
    };
  });
};

// Repository側のDTOからAssigneeオブジェクトを構築する
const createAssignees = (
  permissions: CheckoutPermissionEntity[],
  b2cUserInfo: AdB2cUser[],
): Assignee[] => {
  return permissions.flatMap((x): Assignee[] => {
    if (x.user != null) {
      return [convertUserToAssignee(x.user, b2cUserInfo)];
    }

    if (x.user_group != null) {
      return [convertUserGroupToAssignee(x.user_group)];
    }

    // JOINしようとしたがUserが存在しなかったというケースはSkipする
    return [];
  });
};

// RepositoryDTOのUserからTypistオブジェクトを生成します
const convertUserToAssignee = (
  user: UserEntity,
  b2cUserInfo: AdB2cUser[],
): Assignee => {
  const typistName = b2cUserInfo.find(
    (x) => x.id === user.external_id,
  ).displayName;
  return {
    typistUserId: user.id,
    typistName,
  };
};

// RepositoryDTOのUserGroupからAssigneeオブジェクトを生成します
const convertUserGroupToAssignee = (userGroup: UserGroupEntity): Assignee => {
  return {
    typistGroupId: userGroup.id,
    typistName: userGroup.name,
  };
};

// RepositoryDTOのUserからTypistオブジェクトを生成します
const convertUserToTypist = (
  user: UserEntity,
  b2cUserInfo: AdB2cUser[],
): Typist => {
  const typistName = b2cUserInfo.find(
    (x) => x.id === user.external_id,
  ).displayName;
  return {
    id: user.id,
    name: typistName,
  };
};
